<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://brwiki2.brulescorp.com/brwiki2/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Laura</id>
	<title>BR Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://brwiki2.brulescorp.com/brwiki2/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Laura"/>
	<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Special:Contributions/Laura"/>
	<updated>2026-06-04T05:15:27Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Main_Page&amp;diff=11496</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Main_Page&amp;diff=11496"/>
		<updated>2026-02-13T15:36:43Z</updated>

		<summary type="html">&lt;p&gt;Laura: fixed forum link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{| cellspacing=&amp;quot;12&amp;quot; cellpadding=&amp;quot;15&amp;quot; border=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:Business_Rules_Corp_Logo.png]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Welcome to the &#039;&#039;&#039;{{SITENAME}}&#039;&#039;&#039;. This wiki is dedicated to the &#039;&#039;&#039;[[Business Rules!]]&#039;&#039;&#039; programming language (a.k.a. BR) and the software developers who use it. Business Rules is formerly known as Workstation Basic. Currently containing [[Special:Statistics|{{NUMBEROFARTICLES}}]] articles,  this growing wiki is a great place to find information about the Business Rules! programming language. Our goal is to provide Business Rules! developers a convenient source of reference as well as an easy-to-use platform for documentation development. &lt;br /&gt;
&lt;br /&gt;
We encourage members of the &#039;&#039;&#039;[https://brulescorp.com/brforum.live/ Business Rules! community]&#039;&#039;&#039; to contribute their own knowledge to the Wiki by messaging an editor. A list of editors can be found &#039;&#039;[http://brwiki2.brulescorp.com/index.php?title=Special:ListUsers&amp;amp;group=editor here]&#039;&#039;. &#039;&#039;&#039;New user registration&#039;&#039;&#039; is also performed by editors upon request. Registered users can create discussion pages and send email to other users.&lt;br /&gt;
&lt;br /&gt;
This entire site can be viewed by guests (no login required), while editing content is restricted to the [http://brwiki2.brulescorp.com/index.php?title=Special:ListUsers&amp;amp;group=editor editors group]. Contact &#039;&#039;support@brulescorp.com&#039;&#039; if you wish to become an editor, or wish to know more about the [http://brforum.brulescorp.com Business Rules! community].&lt;br /&gt;
&lt;br /&gt;
If you come here often, you may be interested in just [[Special:Newpages|new pages]] or [[Special:Recentchanges|recent changes]]. &lt;br /&gt;
&lt;br /&gt;
== For New Users ==&lt;br /&gt;
&lt;br /&gt;
*[http://meta.wikimedia.org/wiki/Help:Contents Help Using the Wiki]&lt;br /&gt;
*[[Special:Userlogin|Register]]&lt;br /&gt;
*[[BR Tutorial]]&lt;br /&gt;
*[http://brforum.brulescorp.com BR Forum]&lt;br /&gt;
&lt;br /&gt;
== Main Links ==&lt;br /&gt;
&lt;br /&gt;
*[[Business Rules!|Introduction]]&lt;br /&gt;
*[[BR Reference]]&lt;br /&gt;
*[[Backward Compatibility]]&lt;br /&gt;
*[[:Category:Utilities Third Party|Utilities Third Party]]&lt;br /&gt;
*[http://www.brulescorp.com/brules/download.html#BRUTILITIES Old BR Utilities]&lt;br /&gt;
*[[Export|Exporting the Wiki]]&lt;br /&gt;
*[[Common Categories]]&lt;br /&gt;
&lt;br /&gt;
== Categories  ==&lt;br /&gt;
&lt;br /&gt;
Most of this wiki is categorized. An individual article may belong to multiple categories. The [[Special:Uncategorizedcategories|Top Level Categories]] are a nice way to browse this wiki. In the table below are the most popular categories. &lt;br /&gt;
&lt;br /&gt;
{| width=&amp;quot;50%&amp;quot; cellspacing=&amp;quot;2&amp;quot; cellpadding=&amp;quot;5&amp;quot; border=&amp;quot;1&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Basics|The Basics]]&#039;&#039;&#039; &lt;br /&gt;
*[[:Category:Variable|Variables]]&lt;br /&gt;
*[[:Category:Operations|Operations]]&lt;br /&gt;
*[[:Category:Arrays|Arrays]]&lt;br /&gt;
*[[:Category:Control_Structures|Control Structures]]&lt;br /&gt;
*[[:Category:External_Editors|External Editors]]&lt;br /&gt;
*[[:Category:User_Defined_Functions_and_Libraries|User Defined Functions / Libraries]]&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:GUI|GUI]]&#039;&#039;&#039;   &lt;br /&gt;
* [[:Category:Widget|Widgets]]&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Release Notes|Release Notes]]&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Commands|Commands]]&#039;&#039;&#039; &lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Statements|Statements]]&#039;&#039;&#039; &lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Internal Functions|Internal Functions]]&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Config|Config (Configuration and Environmental Settings)]]&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Terminology|Terminology]]&#039;&#039;&#039; &lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Error|Error]]&#039;&#039;&#039;&lt;br /&gt;
*[[:Category:Error|Error Handling]]&lt;br /&gt;
*[[:Category:Error Codes|Error Codes]]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Files|Files]]&#039;&#039;&#039; &lt;br /&gt;
*[[:Category:File_Operations|File Operations]]&lt;br /&gt;
*[[:Category:Sorting_and_Indexing|Sorting and Indexing]]&lt;br /&gt;
| [[BR Tutorial]]s&lt;br /&gt;
| ...&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Printing|Printing]]&#039;&#039;&#039; &lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Ftp.brulescorp.com|ftp.brulescorp.com]]&#039;&#039;&#039; &lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Utilities Third Party|Utilities Third Party]]&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Procedure Commands|Procedures]]&#039;&#039;&#039; &lt;br /&gt;
| &#039;&#039;&#039;[[:Category:Client Server|Client Server]]&#039;&#039;&#039; &lt;br /&gt;
| ...&lt;br /&gt;
*[[:Category:Field Specifications|Field Specifications]]&lt;br /&gt;
*[[:Category:Definitions|Definitions]]&lt;br /&gt;
*[[:Category:Properties_Events_and_Methods|Properties, Events and Methods]]&lt;br /&gt;
*[[:Category:HTTP|HTTP]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Other Business Rules! Pages on External Links==&lt;br /&gt;
Here are a few places to find other Business Rules! related pages maintained by others.  These are not official pages maintained by [Business Rules Corp].&lt;br /&gt;
&lt;br /&gt;
*[http://www.sageax.com/ Sage AX&#039;s BR page]&lt;br /&gt;
*[http://br32.com/ BR32.com]&lt;br /&gt;
*[http://www.luisgomez.net/br/ Luis Gomez&#039;s BR page]&lt;br /&gt;
*[http://planetacs.net/br/ Advanced Computer Services LLC&#039;s Business Rules! page]&lt;br /&gt;
*[http://planetacs.net/br/npp/index.html Advanced Computer Services LLC&#039;s Notepad++ for Business Rules! page]&lt;br /&gt;
&lt;br /&gt;
==Common Category Trees==&lt;br /&gt;
&lt;br /&gt;
[[Common Categories]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11193</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11193"/>
		<updated>2019-11-19T21:22:07Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Radio Button */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Useful ScreenIO Functions|Useful ScreenIO Functions]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter.&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
  setting_load_filter=0&lt;br /&gt;
  setting_functionsel_filter=1&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
===Load Filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there should be a filter box or a search box on the &amp;quot;Load Screen&amp;quot; dialog (2.3).&lt;br /&gt;
&lt;br /&gt;
===setting_functionsel_filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there is a filter box or a search box on the the &amp;quot;Function Select&amp;quot; dialog screen.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using color attributes, use N=, for example when [BackgroundColor] is set in a config attributes file, use N=[BackgroundColor].&lt;br /&gt;
&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot; (but no quotes). This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control. Fieldtext$ refers to the field that changed and is being validated.&lt;br /&gt;
&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
&lt;br /&gt;
Implement Read and Return keys in the Window Attribute Section because a 0 Read Key will default to a Relative Read.&lt;br /&gt;
&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer. It requires George Tisdale&#039;s rtflib to be installed in a vol002 folder in your app. It can be downloaded from the Sage AX Website here: [[http://www.sageax.com/downloads/vol002.zip]].&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has several [[#Functions_to_use_in_your_ScreenIO_Functions|built in functions]] for use in your events.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
However, if you like, you can use these animations in your own programs, by calling the [[#Animations|ScreenIO Animation Functions]].&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
== Useful ScreenIO Functions ==&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with many useful functions that you can use in your helper functions to interact with ScreenIO, and even a few that you can use in your non-ScreenIO programs. ScreenIO&#039;s Loading Animations, for example, are available for use in any of your BR programs.&lt;br /&gt;
&lt;br /&gt;
=== Functions to use in your ScreenIO Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions are designed to be run from one of your helper functions, to interrogate the current screen and get additional information.&lt;br /&gt;
&lt;br /&gt;
==== fnFunctionBase ====&lt;br /&gt;
&lt;br /&gt;
fnFunctionBase returns the Function Base of the current screen. Use it for interpreting which control was clicked on, in your Mainloop Event.&lt;br /&gt;
&lt;br /&gt;
This function is designed to run from within your screen, from one of your custom functions. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  if fkey-fnFunctionBase=ctl_Name then&lt;br /&gt;
    ! Name field was clicked on&lt;br /&gt;
  &lt;br /&gt;
  end if&lt;br /&gt;
&lt;br /&gt;
==== fnIsOutputSpec and fnIsInputSpec ====&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;boolean&amp;gt;=fnIsOutputSpec(FieldType$)&lt;br /&gt;
  &amp;lt;boolean&amp;gt;=fnIsInputSpec(FieldType$)&lt;br /&gt;
&lt;br /&gt;
These functions are used to tell if ScreenIO would treat the given control as an Input Spec or an output Spec&lt;br /&gt;
  &lt;br /&gt;
They are designed to run from within your screen, from one of your custom functions. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  if fnIsOutputSpec(FieldType$(ControlIndex)) then&lt;br /&gt;
    ! the current control this Validation or Click Event function is running under is a control that ScreenIO would treat as Output Only&lt;br /&gt;
  end if&lt;br /&gt;
&lt;br /&gt;
*Control Index always returns the current control that a Validate or Click event function is running under.&lt;br /&gt;
&lt;br /&gt;
==== fnGetUniqueName$ ====&lt;br /&gt;
&lt;br /&gt;
 In ScreenIO, your controls can all be referenced in Code by their control names. If more then one control share the same control name, ScreenIO creates a unique name by adding the Count to that name. This function returns the Unique Name for a given control, no matter what it is. This does the inverse of fnFindSubscript below, which takes the name and returns the Index.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let msgbox(&amp;quot;The current control has a unique name of &amp;quot;&amp;amp;fnGetUniqueName$(mat ControlName$,ControlIndex)&lt;br /&gt;
&lt;br /&gt;
*Control Index always returns the current control that a Validate or Click event function is running under.&lt;br /&gt;
&lt;br /&gt;
==== fnFindSubscript ====&lt;br /&gt;
&lt;br /&gt;
  fnFindSubscript(MAT Subscripts$,Prefix$,String$*40)&lt;br /&gt;
&lt;br /&gt;
Used to find the Subscript of the control you&#039;re searching for, when you have that controls name as a String. It searches the Subscripts array. This does the inverse of fnGetUniqueName$ above.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let index=fnFindSubscript(mat Subscripts$,&amp;quot;ctl_&amp;quot;,TheNameOfTheControl$)&lt;br /&gt;
&lt;br /&gt;
=== Functions for use in your own programs ===&lt;br /&gt;
&lt;br /&gt;
These functions can be used in any of your programs. They are not specific to any screen and are designed to be called from anywhere.&lt;br /&gt;
 &lt;br /&gt;
==== Animations ====&lt;br /&gt;
&lt;br /&gt;
  let fnPrepareAnimation &lt;br /&gt;
  let fnAnimate(;Text$*60)&lt;br /&gt;
  let fnCloseAnimation&lt;br /&gt;
&lt;br /&gt;
The [[#Working with the ScreenIO Loading Icon|ScreenIO Loading Animations]] can be used in your own programs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let fnPrepareAnimation&lt;br /&gt;
  for SomeReallyLongTask=1 to 1000&lt;br /&gt;
     let fnAnimate(str$(int(100*SomeReallyLongTask/1000))&amp;amp;&amp;quot; percent complete!&amp;quot;)&lt;br /&gt;
     ! Do some long slow thing&lt;br /&gt;
     &lt;br /&gt;
  next SomeReallyLongTask&lt;br /&gt;
  let fnCloseAnimation&lt;br /&gt;
&lt;br /&gt;
==== fnDays ====&lt;br /&gt;
&lt;br /&gt;
  fnDays(UserEnteredDate$*255;DateSpec$*255)&lt;br /&gt;
&lt;br /&gt;
Calls the ScreenIO Days Validation function, which will interpret a wide range of user entered date formats into their corresponding Days value. The DateSpec given is just a general idea - it represents the date spec the user would have seen, and is used to determine the most likely order that the user would have entered the date in, in the event there is ambiguity in the entered data. However, the function is very flexible and will accept a wide variety of date formats entered.&lt;br /&gt;
&lt;br /&gt;
==== fnBr42 and fnBr43 ====&lt;br /&gt;
&lt;br /&gt;
  fnBr42&lt;br /&gt;
  fnBr43&lt;br /&gt;
&lt;br /&gt;
These functions return true if the current copy of BR is equal to or greater then the called function. Internally, ScreenIO uses these functions to disable BR 4.3 only features, when running under BR 4.2. Now, you can use these functions in your programs too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnListSpec$ ====&lt;br /&gt;
&lt;br /&gt;
  fnListSpec$*255(SPECIN$*255)&lt;br /&gt;
&lt;br /&gt;
This function takes a given BR Fields listview spec, and strips off everything after the first 3 commas. It is used to calculate the Listview Base spec when interacting with a listview manually.&lt;br /&gt;
&lt;br /&gt;
=== Functions to interact with the ScreenIO Designer ===&lt;br /&gt;
&lt;br /&gt;
These next few functions can be used to run and interface with the screenio designer directly.&lt;br /&gt;
&lt;br /&gt;
==== fnDesignScreen ====&lt;br /&gt;
&lt;br /&gt;
  fnDesignScreen(;ScreenName$)&lt;br /&gt;
&lt;br /&gt;
This function runs the ScreenIO Designer. If the optional Screen name is given, then that screen is loaded for editing.&lt;br /&gt;
&lt;br /&gt;
==== fnSelectEvent$ ====&lt;br /&gt;
&lt;br /&gt;
  fnSelectEvent$*255(Current$*255;&amp;amp;ReturnFkey)&lt;br /&gt;
&lt;br /&gt;
This function loads the ScreenIO Select Event Function dialog. You pass in whatever the current user selection is, and it allows the user to change that selection using the standard Event Function selection dialog and returns the result.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list shows some of the change requests that have been completed.&lt;br /&gt;
&lt;br /&gt;
For a complete list, see the recentChanges.txt file that comes with ScreenIO, which can be found by going to the ScreenIO windows dropdown Help menu, and choosing &amp;quot;Recent Changes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11162</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11162"/>
		<updated>2019-09-16T22:28:30Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Validation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Useful ScreenIO Functions|Useful ScreenIO Functions]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter.&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
  setting_load_filter=0&lt;br /&gt;
  setting_functionsel_filter=1&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
===Load Filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there should be a filter box or a search box on the &amp;quot;Load Screen&amp;quot; dialog (2.3).&lt;br /&gt;
&lt;br /&gt;
===setting_functionsel_filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there is a filter box or a search box on the the &amp;quot;Function Select&amp;quot; dialog screen.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using color attributes, use N=, for example when [BackgroundColor] is set in a config attributes file, use N=[BackgroundColor].&lt;br /&gt;
&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control. Fieldtext$ refers to the field that changed and is being validated.&lt;br /&gt;
&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
&lt;br /&gt;
Implement Read and Return keys in the Window Attribute Section because a 0 Read Key will default to a Relative Read.&lt;br /&gt;
&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer. It requires George Tisdale&#039;s rtflib to be installed in a vol002 folder in your app. It can be downloaded from the Sage AX Website here: [[http://www.sageax.com/downloads/vol002.zip]].&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has several [[#Functions_to_use_in_your_ScreenIO_Functions|built in functions]] for use in your events.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
However, if you like, you can use these animations in your own programs, by calling the [[#Animations|ScreenIO Animation Functions]].&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
== Useful ScreenIO Functions ==&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with many useful functions that you can use in your helper functions to interact with ScreenIO, and even a few that you can use in your non-ScreenIO programs. ScreenIO&#039;s Loading Animations, for example, are available for use in any of your BR programs.&lt;br /&gt;
&lt;br /&gt;
=== Functions to use in your ScreenIO Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions are designed to be run from one of your helper functions, to interrogate the current screen and get additional information.&lt;br /&gt;
&lt;br /&gt;
==== fnFunctionBase ====&lt;br /&gt;
&lt;br /&gt;
fnFunctionBase returns the Function Base of the current screen. Use it for interpreting which control was clicked on, in your Mainloop Event.&lt;br /&gt;
&lt;br /&gt;
This function is designed to run from within your screen, from one of your custom functions. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  if fkey-fnFunctionBase=ctl_Name then&lt;br /&gt;
    ! Name field was clicked on&lt;br /&gt;
  &lt;br /&gt;
  end if&lt;br /&gt;
&lt;br /&gt;
==== fnIsOutputSpec and fnIsInputSpec ====&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;boolean&amp;gt;=fnIsOutputSpec(FieldType$)&lt;br /&gt;
  &amp;lt;boolean&amp;gt;=fnIsInputSpec(FieldType$)&lt;br /&gt;
&lt;br /&gt;
These functions are used to tell if ScreenIO would treat the given control as an Input Spec or an output Spec&lt;br /&gt;
  &lt;br /&gt;
They are designed to run from within your screen, from one of your custom functions. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  if fnIsOutputSpec(FieldType$(ControlIndex)) then&lt;br /&gt;
    ! the current control this Validation or Click Event function is running under is a control that ScreenIO would treat as Output Only&lt;br /&gt;
  end if&lt;br /&gt;
&lt;br /&gt;
*Control Index always returns the current control that a Validate or Click event function is running under.&lt;br /&gt;
&lt;br /&gt;
==== fnGetUniqueName$ ====&lt;br /&gt;
&lt;br /&gt;
 In ScreenIO, your controls can all be referenced in Code by their control names. If more then one control share the same control name, ScreenIO creates a unique name by adding the Count to that name. This function returns the Unique Name for a given control, no matter what it is. This does the inverse of fnFindSubscript below, which takes the name and returns the Index.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let msgbox(&amp;quot;The current control has a unique name of &amp;quot;&amp;amp;fnGetUniqueName$(mat ControlName$,ControlIndex)&lt;br /&gt;
&lt;br /&gt;
*Control Index always returns the current control that a Validate or Click event function is running under.&lt;br /&gt;
&lt;br /&gt;
==== fnFindSubscript ====&lt;br /&gt;
&lt;br /&gt;
  fnFindSubscript(MAT Subscripts$,Prefix$,String$*40)&lt;br /&gt;
&lt;br /&gt;
Used to find the Subscript of the control you&#039;re searching for, when you have that controls name as a String. It searches the Subscripts array. This does the inverse of fnGetUniqueName$ above.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let index=fnFindSubscript(mat Subscripts$,&amp;quot;ctl_&amp;quot;,TheNameOfTheControl$)&lt;br /&gt;
&lt;br /&gt;
=== Functions for use in your own programs ===&lt;br /&gt;
&lt;br /&gt;
These functions can be used in any of your programs. They are not specific to any screen and are designed to be called from anywhere.&lt;br /&gt;
 &lt;br /&gt;
==== Animations ====&lt;br /&gt;
&lt;br /&gt;
  let fnPrepareAnimation &lt;br /&gt;
  let fnAnimate(;Text$*60)&lt;br /&gt;
  let fnCloseAnimation&lt;br /&gt;
&lt;br /&gt;
The [[#Working with the ScreenIO Loading Icon|ScreenIO Loading Animations]] can be used in your own programs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let fnPrepareAnimation&lt;br /&gt;
  for SomeReallyLongTask=1 to 1000&lt;br /&gt;
     let fnAnimate(str$(int(100*SomeReallyLongTask/1000))&amp;amp;&amp;quot; percent complete!&amp;quot;)&lt;br /&gt;
     ! Do some long slow thing&lt;br /&gt;
     &lt;br /&gt;
  next SomeReallyLongTask&lt;br /&gt;
  let fnCloseAnimation&lt;br /&gt;
&lt;br /&gt;
==== fnDays ====&lt;br /&gt;
&lt;br /&gt;
  fnDays(UserEnteredDate$*255;DateSpec$*255)&lt;br /&gt;
&lt;br /&gt;
Calls the ScreenIO Days Validation function, which will interpret a wide range of user entered date formats into their corresponding Days value. The DateSpec given is just a general idea - it represents the date spec the user would have seen, and is used to determine the most likely order that the user would have entered the date in, in the event there is ambiguity in the entered data. However, the function is very flexible and will accept a wide variety of date formats entered.&lt;br /&gt;
&lt;br /&gt;
==== fnBr42 and fnBr43 ====&lt;br /&gt;
&lt;br /&gt;
  fnBr42&lt;br /&gt;
  fnBr43&lt;br /&gt;
&lt;br /&gt;
These functions return true if the current copy of BR is equal to or greater then the called function. Internally, ScreenIO uses these functions to disable BR 4.3 only features, when running under BR 4.2. Now, you can use these functions in your programs too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnListSpec$ ====&lt;br /&gt;
&lt;br /&gt;
  fnListSpec$*255(SPECIN$*255)&lt;br /&gt;
&lt;br /&gt;
This function takes a given BR Fields listview spec, and strips off everything after the first 3 commas. It is used to calculate the Listview Base spec when interacting with a listview manually.&lt;br /&gt;
&lt;br /&gt;
=== Functions to interact with the ScreenIO Designer ===&lt;br /&gt;
&lt;br /&gt;
These next few functions can be used to run and interface with the screenio designer directly.&lt;br /&gt;
&lt;br /&gt;
==== fnDesignScreen ====&lt;br /&gt;
&lt;br /&gt;
  fnDesignScreen(;ScreenName$)&lt;br /&gt;
&lt;br /&gt;
This function runs the ScreenIO Designer. If the optional Screen name is given, then that screen is loaded for editing.&lt;br /&gt;
&lt;br /&gt;
==== fnSelectEvent$ ====&lt;br /&gt;
&lt;br /&gt;
  fnSelectEvent$*255(Current$*255;&amp;amp;ReturnFkey)&lt;br /&gt;
&lt;br /&gt;
This function loads the ScreenIO Select Event Function dialog. You pass in whatever the current user selection is, and it allows the user to change that selection using the standard Event Function selection dialog and returns the result.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list shows some of the change requests that have been completed.&lt;br /&gt;
&lt;br /&gt;
For a complete list, see the recentChanges.txt file that comes with ScreenIO, which can be found by going to the ScreenIO windows dropdown Help menu, and choosing &amp;quot;Recent Changes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11161</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11161"/>
		<updated>2019-09-15T18:37:37Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Useful ScreenIO Functions|Useful ScreenIO Functions]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter.&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
  setting_load_filter=0&lt;br /&gt;
  setting_functionsel_filter=1&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
===Load Filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there should be a filter box or a search box on the &amp;quot;Load Screen&amp;quot; dialog (2.3).&lt;br /&gt;
&lt;br /&gt;
===setting_functionsel_filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there is a filter box or a search box on the the &amp;quot;Function Select&amp;quot; dialog screen.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using color attributes, use N=, for example when [BackgroundColor] is set in a config attributes file, use N=[BackgroundColor].&lt;br /&gt;
&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
&lt;br /&gt;
Implement Read and Return keys in the Window Attribute Section because a 0 Read Key will default to a Relative Read.&lt;br /&gt;
&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer. It requires George Tisdale&#039;s rtflib to be installed in a vol002 folder in your app. It can be downloaded from the Sage AX Website here: [[http://www.sageax.com/downloads/vol002.zip]].&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has several [[#Functions_to_use_in_your_ScreenIO_Functions|built in functions]] for use in your events.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
However, if you like, you can use these animations in your own programs, by calling the [[#Animations|ScreenIO Animation Functions]].&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
== Useful ScreenIO Functions ==&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with many useful functions that you can use in your helper functions to interact with ScreenIO, and even a few that you can use in your non-ScreenIO programs. ScreenIO&#039;s Loading Animations, for example, are available for use in any of your BR programs.&lt;br /&gt;
&lt;br /&gt;
=== Functions to use in your ScreenIO Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions are designed to be run from one of your helper functions, to interrogate the current screen and get additional information.&lt;br /&gt;
&lt;br /&gt;
==== fnFunctionBase ====&lt;br /&gt;
&lt;br /&gt;
fnFunctionBase returns the Function Base of the current screen. Use it for interpreting which control was clicked on, in your Mainloop Event.&lt;br /&gt;
&lt;br /&gt;
This function is designed to run from within your screen, from one of your custom functions. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  if fkey-fnFunctionBase=ctl_Name then&lt;br /&gt;
    ! Name field was clicked on&lt;br /&gt;
  &lt;br /&gt;
  end if&lt;br /&gt;
&lt;br /&gt;
==== fnIsOutputSpec and fnIsInputSpec ====&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;boolean&amp;gt;=fnIsOutputSpec(FieldType$)&lt;br /&gt;
  &amp;lt;boolean&amp;gt;=fnIsInputSpec(FieldType$)&lt;br /&gt;
&lt;br /&gt;
These functions are used to tell if ScreenIO would treat the given control as an Input Spec or an output Spec&lt;br /&gt;
  &lt;br /&gt;
They are designed to run from within your screen, from one of your custom functions. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  if fnIsOutputSpec(FieldType$(ControlIndex)) then&lt;br /&gt;
    ! the current control this Validation or Click Event function is running under is a control that ScreenIO would treat as Output Only&lt;br /&gt;
  end if&lt;br /&gt;
&lt;br /&gt;
*Control Index always returns the current control that a Validate or Click event function is running under.&lt;br /&gt;
&lt;br /&gt;
==== fnGetUniqueName$ ====&lt;br /&gt;
&lt;br /&gt;
 In ScreenIO, your controls can all be referenced in Code by their control names. If more then one control share the same control name, ScreenIO creates a unique name by adding the Count to that name. This function returns the Unique Name for a given control, no matter what it is. This does the inverse of fnFindSubscript below, which takes the name and returns the Index.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let msgbox(&amp;quot;The current control has a unique name of &amp;quot;&amp;amp;fnGetUniqueName$(mat ControlName$,ControlIndex)&lt;br /&gt;
&lt;br /&gt;
*Control Index always returns the current control that a Validate or Click event function is running under.&lt;br /&gt;
&lt;br /&gt;
==== fnFindSubscript ====&lt;br /&gt;
&lt;br /&gt;
  fnFindSubscript(MAT Subscripts$,Prefix$,String$*40)&lt;br /&gt;
&lt;br /&gt;
Used to find the Subscript of the control you&#039;re searching for, when you have that controls name as a String. It searches the Subscripts array. This does the inverse of fnGetUniqueName$ above.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let index=fnFindSubscript(mat Subscripts$,&amp;quot;ctl_&amp;quot;,TheNameOfTheControl$)&lt;br /&gt;
&lt;br /&gt;
=== Functions for use in your own programs ===&lt;br /&gt;
&lt;br /&gt;
These functions can be used in any of your programs. They are not specific to any screen and are designed to be called from anywhere.&lt;br /&gt;
 &lt;br /&gt;
==== Animations ====&lt;br /&gt;
&lt;br /&gt;
  let fnPrepareAnimation &lt;br /&gt;
  let fnAnimate(;Text$*60)&lt;br /&gt;
  let fnCloseAnimation&lt;br /&gt;
&lt;br /&gt;
The [[#Working with the ScreenIO Loading Icon|ScreenIO Loading Animations]] can be used in your own programs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let fnPrepareAnimation&lt;br /&gt;
  for SomeReallyLongTask=1 to 1000&lt;br /&gt;
     let fnAnimate(str$(int(100*SomeReallyLongTask/1000))&amp;amp;&amp;quot; percent complete!&amp;quot;)&lt;br /&gt;
     ! Do some long slow thing&lt;br /&gt;
     &lt;br /&gt;
  next SomeReallyLongTask&lt;br /&gt;
  let fnCloseAnimation&lt;br /&gt;
&lt;br /&gt;
==== fnDays ====&lt;br /&gt;
&lt;br /&gt;
  fnDays(UserEnteredDate$*255;DateSpec$*255)&lt;br /&gt;
&lt;br /&gt;
Calls the ScreenIO Days Validation function, which will interpret a wide range of user entered date formats into their corresponding Days value. The DateSpec given is just a general idea - it represents the date spec the user would have seen, and is used to determine the most likely order that the user would have entered the date in, in the event there is ambiguity in the entered data. However, the function is very flexible and will accept a wide variety of date formats entered.&lt;br /&gt;
&lt;br /&gt;
==== fnBr42 and fnBr43 ====&lt;br /&gt;
&lt;br /&gt;
  fnBr42&lt;br /&gt;
  fnBr43&lt;br /&gt;
&lt;br /&gt;
These functions return true if the current copy of BR is equal to or greater then the called function. Internally, ScreenIO uses these functions to disable BR 4.3 only features, when running under BR 4.2. Now, you can use these functions in your programs too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnListSpec$ ====&lt;br /&gt;
&lt;br /&gt;
  fnListSpec$*255(SPECIN$*255)&lt;br /&gt;
&lt;br /&gt;
This function takes a given BR Fields listview spec, and strips off everything after the first 3 commas. It is used to calculate the Listview Base spec when interacting with a listview manually.&lt;br /&gt;
&lt;br /&gt;
=== Functions to interact with the ScreenIO Designer ===&lt;br /&gt;
&lt;br /&gt;
These next few functions can be used to run and interface with the screenio designer directly.&lt;br /&gt;
&lt;br /&gt;
==== fnDesignScreen ====&lt;br /&gt;
&lt;br /&gt;
  fnDesignScreen(;ScreenName$)&lt;br /&gt;
&lt;br /&gt;
This function runs the ScreenIO Designer. If the optional Screen name is given, then that screen is loaded for editing.&lt;br /&gt;
&lt;br /&gt;
==== fnSelectEvent$ ====&lt;br /&gt;
&lt;br /&gt;
  fnSelectEvent$*255(Current$*255;&amp;amp;ReturnFkey)&lt;br /&gt;
&lt;br /&gt;
This function loads the ScreenIO Select Event Function dialog. You pass in whatever the current user selection is, and it allows the user to change that selection using the standard Event Function selection dialog and returns the result.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list shows some of the change requests that have been completed.&lt;br /&gt;
&lt;br /&gt;
For a complete list, see the recentChanges.txt file that comes with ScreenIO, which can be found by going to the ScreenIO windows dropdown Help menu, and choosing &amp;quot;Recent Changes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11157</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11157"/>
		<updated>2019-08-27T20:40:34Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Attributes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Useful ScreenIO Functions|Useful ScreenIO Functions]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter.&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
  setting_load_filter=0&lt;br /&gt;
  setting_functionsel_filter=1&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
===Load Filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there should be a filter box or a search box on the &amp;quot;Load Screen&amp;quot; dialog (2.3).&lt;br /&gt;
&lt;br /&gt;
===setting_functionsel_filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there is a filter box or a search box on the the &amp;quot;Function Select&amp;quot; dialog screen.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using color attributes, use N=, for example when [BackgroundColor] is set in a config attributes file, use N=[BackgroundColor].&lt;br /&gt;
&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer. It requires George Tisdale&#039;s rtflib to be installed in a vol002 folder in your app. It can be downloaded from the Sage AX Website here: [[http://www.sageax.com/downloads/vol002.zip]].&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has several [[#Functions_to_use_in_your_ScreenIO_Functions|built in functions]] for use in your events.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
However, if you like, you can use these animations in your own programs, by calling the [[#Animations|ScreenIO Animation Functions]].&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
== Useful ScreenIO Functions ==&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with many useful functions that you can use in your helper functions to interact with ScreenIO, and even a few that you can use in your non-ScreenIO programs. ScreenIO&#039;s Loading Animations, for example, are available for use in any of your BR programs.&lt;br /&gt;
&lt;br /&gt;
=== Functions to use in your ScreenIO Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions are designed to be run from one of your helper functions, to interrogate the current screen and get additional information.&lt;br /&gt;
&lt;br /&gt;
==== fnFunctionBase ====&lt;br /&gt;
&lt;br /&gt;
fnFunctionBase returns the Function Base of the current screen. Use it for interpreting which control was clicked on, in your Mainloop Event.&lt;br /&gt;
&lt;br /&gt;
This function is designed to run from within your screen, from one of your custom functions. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  if fkey-fnFunctionBase=ctl_Name then&lt;br /&gt;
    ! Name field was clicked on&lt;br /&gt;
  &lt;br /&gt;
  end if&lt;br /&gt;
&lt;br /&gt;
==== fnIsOutputSpec and fnIsInputSpec ====&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;boolean&amp;gt;=fnIsOutputSpec(FieldType$)&lt;br /&gt;
  &amp;lt;boolean&amp;gt;=fnIsInputSpec(FieldType$)&lt;br /&gt;
&lt;br /&gt;
These functions are used to tell if ScreenIO would treat the given control as an Input Spec or an output Spec&lt;br /&gt;
  &lt;br /&gt;
They are designed to run from within your screen, from one of your custom functions. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  if fnIsOutputSpec(FieldType$(ControlIndex)) then&lt;br /&gt;
    ! the current control this Validation or Click Event function is running under is a control that ScreenIO would treat as Output Only&lt;br /&gt;
  end if&lt;br /&gt;
&lt;br /&gt;
*Control Index always returns the current control that a Validate or Click event function is running under.&lt;br /&gt;
&lt;br /&gt;
==== fnGetUniqueName$ ====&lt;br /&gt;
&lt;br /&gt;
 In ScreenIO, your controls can all be referenced in Code by their control names. If more then one control share the same control name, ScreenIO creates a unique name by adding the Count to that name. This function returns the Unique Name for a given control, no matter what it is. This does the inverse of fnFindSubscript below, which takes the name and returns the Index.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let msgbox(&amp;quot;The current control has a unique name of &amp;quot;&amp;amp;fnGetUniqueName$(mat ControlName$,ControlIndex)&lt;br /&gt;
&lt;br /&gt;
*Control Index always returns the current control that a Validate or Click event function is running under.&lt;br /&gt;
&lt;br /&gt;
==== fnFindSubscript ====&lt;br /&gt;
&lt;br /&gt;
  fnFindSubscript(MAT Subscripts$,Prefix$,String$*40)&lt;br /&gt;
&lt;br /&gt;
Used to find the Subscript of the control you&#039;re searching for, when you have that controls name as a String. It searches the Subscripts array. This does the inverse of fnGetUniqueName$ above.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let index=fnFindSubscript(mat Subscripts$,&amp;quot;ctl_&amp;quot;,TheNameOfTheControl$)&lt;br /&gt;
&lt;br /&gt;
=== Functions for use in your own programs ===&lt;br /&gt;
&lt;br /&gt;
These functions can be used in any of your programs. They are not specific to any screen and are designed to be called from anywhere.&lt;br /&gt;
 &lt;br /&gt;
==== Animations ====&lt;br /&gt;
&lt;br /&gt;
  let fnPrepareAnimation &lt;br /&gt;
  let fnAnimate(;Text$*60)&lt;br /&gt;
  let fnCloseAnimation&lt;br /&gt;
&lt;br /&gt;
The [[#Working with the ScreenIO Loading Icon|ScreenIO Loading Animations]] can be used in your own programs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  let fnPrepareAnimation&lt;br /&gt;
  for SomeReallyLongTask=1 to 1000&lt;br /&gt;
     let fnAnimate(str$(int(100*SomeReallyLongTask/1000))&amp;amp;&amp;quot; percent complete!&amp;quot;)&lt;br /&gt;
     ! Do some long slow thing&lt;br /&gt;
     &lt;br /&gt;
  next SomeReallyLongTask&lt;br /&gt;
  let fnCloseAnimation&lt;br /&gt;
&lt;br /&gt;
==== fnDays ====&lt;br /&gt;
&lt;br /&gt;
  fnDays(UserEnteredDate$*255;DateSpec$*255)&lt;br /&gt;
&lt;br /&gt;
Calls the ScreenIO Days Validation function, which will interpret a wide range of user entered date formats into their corresponding Days value. The DateSpec given is just a general idea - it represents the date spec the user would have seen, and is used to determine the most likely order that the user would have entered the date in, in the event there is ambiguity in the entered data. However, the function is very flexible and will accept a wide variety of date formats entered.&lt;br /&gt;
&lt;br /&gt;
==== fnBr42 and fnBr43 ====&lt;br /&gt;
&lt;br /&gt;
  fnBr42&lt;br /&gt;
  fnBr43&lt;br /&gt;
&lt;br /&gt;
These functions return true if the current copy of BR is equal to or greater then the called function. Internally, ScreenIO uses these functions to disable BR 4.3 only features, when running under BR 4.2. Now, you can use these functions in your programs too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnListSpec$ ====&lt;br /&gt;
&lt;br /&gt;
  fnListSpec$*255(SPECIN$*255)&lt;br /&gt;
&lt;br /&gt;
This function takes a given BR Fields listview spec, and strips off everything after the first 3 commas. It is used to calculate the Listview Base spec when interacting with a listview manually.&lt;br /&gt;
&lt;br /&gt;
=== Functions to interact with the ScreenIO Designer ===&lt;br /&gt;
&lt;br /&gt;
These next few functions can be used to run and interface with the screenio designer directly.&lt;br /&gt;
&lt;br /&gt;
==== fnDesignScreen ====&lt;br /&gt;
&lt;br /&gt;
  fnDesignScreen(;ScreenName$)&lt;br /&gt;
&lt;br /&gt;
This function runs the ScreenIO Designer. If the optional Screen name is given, then that screen is loaded for editing.&lt;br /&gt;
&lt;br /&gt;
==== fnSelectEvent$ ====&lt;br /&gt;
&lt;br /&gt;
  fnSelectEvent$*255(Current$*255;&amp;amp;ReturnFkey)&lt;br /&gt;
&lt;br /&gt;
This function loads the ScreenIO Select Event Function dialog. You pass in whatever the current user selection is, and it allows the user to change that selection using the standard Event Function selection dialog and returns the result.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list shows some of the change requests that have been completed.&lt;br /&gt;
&lt;br /&gt;
For a complete list, see the recentChanges.txt file that comes with ScreenIO, which can be found by going to the ScreenIO windows dropdown Help menu, and choosing &amp;quot;Recent Changes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=2280&amp;diff=11090</id>
		<title>2280</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=2280&amp;diff=11090"/>
		<updated>2019-05-22T18:06:35Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Error&lt;br /&gt;
|2280&lt;br /&gt;
|[[Library]] not executable&lt;br /&gt;
|A [[Load]] [[Resident]] [[command]] was issued for a library [[program]] that is not executable. The Load operation was not performed.&lt;br /&gt;
|Fix the bug in the library [[program]], execute [[Clear Resident]] and run your program again.&lt;br /&gt;
If you get this in a screenio screen, then load and replace it (lo screenio\screenname, rep) to find the real location of the error.&lt;br /&gt;
}}&lt;br /&gt;
[[Category:Error Codes]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=2280&amp;diff=11089</id>
		<title>2280</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=2280&amp;diff=11089"/>
		<updated>2019-05-22T17:54:56Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Error&lt;br /&gt;
|2280&lt;br /&gt;
|[[Library]] not executable&lt;br /&gt;
|A [[Load]] [[Resident]] [[command]] was issued for a library [[program]] that is not executable. The Load operation was not performed.&lt;br /&gt;
|Fix the bug in the library [[program]], execute [[Clear Resident]] and run your program again.&lt;br /&gt;
If you get this in a screenio screen, then load and replace it to find the real location of the error.&lt;br /&gt;
}}&lt;br /&gt;
[[Category:Error Codes]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11021</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11021"/>
		<updated>2018-09-20T16:38:39Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Load Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
  setting_load_filter=0&lt;br /&gt;
  setting_functionsel_filter=1&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
===Load Filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there should be a filter box or a search box on the &amp;quot;Load Screen&amp;quot; dialog (2.3).&lt;br /&gt;
&lt;br /&gt;
===setting_functionsel_filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there is a filter box or a search box on the the &amp;quot;Function Select&amp;quot; dialog screen.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer.&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11020</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11020"/>
		<updated>2018-09-20T16:38:28Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* setting_functionsel_filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
  setting_load_filter=0&lt;br /&gt;
  setting_functionsel_filter=1&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
===Load Filter===&lt;br /&gt;
&lt;br /&gt;
Control weather there should be a filter box or a search box on the &amp;quot;Load Screen&amp;quot; dialog (2.3).&lt;br /&gt;
&lt;br /&gt;
===setting_functionsel_filter===&lt;br /&gt;
&lt;br /&gt;
Controls weather there is a filter box or a search box on the the &amp;quot;Function Select&amp;quot; dialog screen.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer.&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11019</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11019"/>
		<updated>2018-09-20T16:37:50Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* setting_load_filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
  setting_load_filter=0&lt;br /&gt;
  setting_functionsel_filter=1&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
===Load Filter===&lt;br /&gt;
&lt;br /&gt;
Control weather there should be a filter box or a search box on the &amp;quot;Load Screen&amp;quot; dialog (2.3).&lt;br /&gt;
&lt;br /&gt;
===setting_functionsel_filter===&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer.&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11018</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11018"/>
		<updated>2018-09-20T16:28:23Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Screenio.ini */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
  setting_load_filter=0&lt;br /&gt;
  setting_functionsel_filter=1&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
===setting_load_filter===&lt;br /&gt;
&lt;br /&gt;
===setting_functionsel_filter===&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer.&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=FileIO_Library&amp;diff=11017</id>
		<title>FileIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=FileIO_Library&amp;diff=11017"/>
		<updated>2018-09-20T15:46:51Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* fnReadFormAndSubs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;FileIO&#039;&#039;&#039; Library began as a project to find a way to reduce the headache associated with making changes to data files. In my experiences working for [[BRC]], I had to make a change to the commun file, a data file that stores information about communication with EDI VANs. I added some new fields, and removed a couple of old fields, and then I began searching through the BRC program suite to find and modify each program that referenced this data file in order to update it with the proper new form statement. This task quickly became daunting as I noticed that out of BRC’s program suite of over 600 programs, more than one third of them referenced the commun file. With 223 programs to modify, the task was given up as hopeless and tabled indefinitely.&lt;br /&gt;
&lt;br /&gt;
I am happy to announce that we have solved this problem. When I have to make a change to a data file layout for my customers today, I can complete the task in under 1 minute, and not a single program needs to be changed in order to continue working with the new file layout. In fact, I don’t even have to update my customer’s data files, as the FileIO library takes care of this for me as well.&lt;br /&gt;
&lt;br /&gt;
The trick is to define your file layouts in an ASCII text file layout file that I will tell you about in a minute. The FileIO Library will actually parse through your file layouts, and it will instruct your programs how to read the data file, so that you don’t have to. It will also automatically detect when you make changes to the file layout, and it will update your customer’s data files on the fly to make sure they have the latest version. Finally, it even contains a DataCrawler that you can use to examine the contents of any of your BR data files in a raw format.&lt;br /&gt;
&lt;br /&gt;
For more information about the FileIO Library visit the [http://www.sageax.com/products/fileio-library/ Sage AX Website]&lt;br /&gt;
&lt;br /&gt;
To download the latest copy of FileIO, click [http://www.sageax.com/downloads/FileIO.zip here.]&lt;br /&gt;
&lt;br /&gt;
== Method of Operation ==&lt;br /&gt;
The file IO library parses a formatted text file layout and uses this information to structure the opening and initializing of the reading of a file “object”. The word object here is used to refer to all the data in a given record layout in one of your files. This library is easy to use, and provided you follow some simple standards, it will simplify your life immensely.&lt;br /&gt;
&lt;br /&gt;
You will need to define one array for all forms and add a snippet of code (given below) to the program for interfacing with with the library. For each file you will need to define a couple of arrays and use the library to open them. From that point on access to data is simple and direct. &lt;br /&gt;
&lt;br /&gt;
=== File Object Arrays ===&lt;br /&gt;
&lt;br /&gt;
First, in your program you must create two arrays to store the file information. If we are dealing with the Color File these would be MAT COLOR$ and MAT COLOR. One will store all the string information about a color, and the other will store all the numeric data. Our working example will involve two files: a Color File and a Color Category File. You should dimension these to:&lt;br /&gt;
&lt;br /&gt;
  01030    DIM color$(1)*1000,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*1000,colorcat(1)&lt;br /&gt;
&lt;br /&gt;
We&#039;re dimensioning the string arrays to 1000. This is the length of one field in the color file. It needs to be at least as big as the largest string field in the data file.&lt;br /&gt;
&lt;br /&gt;
However, it is recommended to make sure the length is long enough to handle any field you might eventually add to the file at any point in the future. BR supports multi-line textboxes, so I sometimes add long memo fields to my data files that might be 400 or 800 or even 1000 characters long, therefore 1000 is the length I use now in all my new development.&lt;br /&gt;
&lt;br /&gt;
But anything will work as long as its long enough to handle the largest data field in your file.&lt;br /&gt;
&lt;br /&gt;
=== Forms Array ===&lt;br /&gt;
&lt;br /&gt;
You will also need a variable to store the form statement associated with reading the files. This form statement will be dynamically generated whenever a new file is opened. It will say: &lt;br /&gt;
&lt;br /&gt;
  01020    DIM form$(1)*255&lt;br /&gt;
&lt;br /&gt;
This form statement will be compiled by the FileIO open statement and BR limits all form statements to 255 bytes compiled anyway, so 255 is enough for the Forms$ array.&lt;br /&gt;
&lt;br /&gt;
=== Library Linkage ===&lt;br /&gt;
&lt;br /&gt;
You will also need the library statement:&lt;br /&gt;
&lt;br /&gt;
  02020 library &amp;quot;fileio.br&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
&lt;br /&gt;
=== fnOpen Function ===&lt;br /&gt;
&lt;br /&gt;
Now, add a snippet of code to interface with the library.&lt;br /&gt;
&lt;br /&gt;
Because BR libraries do not share variables with the programs they are called from, we will need to execute a proc file whenever we open a file to set the names of all our variables after we return. Add the following snippet of code into your program. It will create an FnOpen function that calls the library version and runs the proc file. The $$$ at the end of the procfile name tells the procfile to self-destruct after execution. Since this procfile is used simply to return variable information back from the library to the main program, we don’t need it sitting around collecting dust.&lt;br /&gt;
&lt;br /&gt;
  99010 OPEN: ! ***** Function To Call Library Openfile And Proc Subs&lt;br /&gt;
  99020    def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths,Supress_Prompt,Ignore_Errors,Suppress_Log,___,Index)&lt;br /&gt;
  99030       dim _FileIOSubs$(1)*800, _Loadedsubs$(1)*80&lt;br /&gt;
  99040       let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$, Supress_Prompt,Ignore_Errors,Program$,Suppress_Log)&lt;br /&gt;
  99050       if Srch(_Loadedsubs$,Uprc$(Filename$))&amp;lt;=0 then : mat _Loadedsubs$(Udim(_Loadedsubs$)+1) : let _Loadedsubs$(Udim(_Loadedsubs$))=Uprc$(Filename$) : for Index=1 to Udim(Mat _Fileiosubs$) : execute (_Fileiosubs$(Index)) : next Index&lt;br /&gt;
  99060    fnend&lt;br /&gt;
&lt;br /&gt;
Or, for those with [[Lexi]]:&lt;br /&gt;
  OPEN: ! ***** Function To Call Library Openfile And Proc Subs&lt;br /&gt;
     def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths,Supress_Prompt,Ignore_Errors,Suppress_Log,___,Index)&lt;br /&gt;
        dim _FileIOSubs$(1)*800, _Loadedsubs$(1)*80&lt;br /&gt;
        let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$, Supress_Prompt,Ignore_Errors,Program$,Suppress_Log)&lt;br /&gt;
        if Srch(_Loadedsubs$,Uprc$(Filename$))&amp;lt;=0 then : mat _Loadedsubs$(Udim(_Loadedsubs$)+1) : let _Loadedsubs$(Udim(_Loadedsubs$))=Uprc$(Filename$) : for Index=1 to Udim(Mat _Fileiosubs$) : execute (_Fileiosubs$(Index)) : next Index&lt;br /&gt;
     fnend&lt;br /&gt;
&lt;br /&gt;
=== Using FileIO in Your Programs ===&lt;br /&gt;
Now you are ready to process files. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;You simply open the files by saying:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;read each file as follows:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  30120    read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore  &lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;and access the data:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  30180    LET ColorCode$=color$(co_Code) !:&lt;br /&gt;
           LET ColorName$=color$(co_Name)&lt;br /&gt;
&lt;br /&gt;
=== How it Works ===&lt;br /&gt;
These statements tell the File Library to look in the filelay folder to find the file layout for the Color File, and read it to find out what the Color File looks like. Then Open the Color File, and set MAT COLOR$ and MAT COLOR to the correct number of elements to hold an entire color record. Finally, it will define several variables that we can use as pointers into (subscripts) these arrays to access the data we after reading it, and it will place the file handle into a variable called colorfile.&lt;br /&gt;
&lt;br /&gt;
The second open above will do the same thing to the color category file, except the 1 parameter tells the function to open readonly. The subscripts array will be executed, creating the subscripts in memory, and the pointers (subscripts) will be set in the calling program. So, if I had a file layout such as the following:&lt;br /&gt;
&lt;br /&gt;
  color.dat, CO_, 1&lt;br /&gt;
  color.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Color Code,                  C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  CATEGORY$,      General Category of Color,   C    6&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
&lt;br /&gt;
Then the functions would do the same thing as the following individual lines of code (assuming the next available file handle was 5):&lt;br /&gt;
&lt;br /&gt;
  DIM FORM$(5)*255&lt;br /&gt;
  DIM COLOR$(9)*1023, COLOR(1)&lt;br /&gt;
  OPEN #5: “Name=color.dat, kfname=color.key”,internal,outin,keyed&lt;br /&gt;
  LET FORM$(5)=”form C 6,V 30,V 6,C 6”&lt;br /&gt;
  LET FORM$(5)=CFORM$(FORM$(5))&lt;br /&gt;
  LET COLORFILE=5&lt;br /&gt;
  CO_CODE=1&lt;br /&gt;
  CO_NAME=2&lt;br /&gt;
  CO_CATEGORY=3&lt;br /&gt;
  CO_HTML=4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The data is used by referencing the file array, with the subscript name, so the color’s description becomes color$(co_Name).&lt;br /&gt;
&lt;br /&gt;
In the old days, if we wanted to change the file layout of our file, all of the programs that used that file would have to be changed one at a time to use the new file layout. Also, if the order of the fields changed, then all the programs would have to also be changed to use the new fields.&lt;br /&gt;
&lt;br /&gt;
But now, using this function, we can change the file layout all we want. If we later want to insert a field into the file layout before color name, I won’t have to look at this program again; this program will just work fine, because the library maps the subscripts to the actual fields.&lt;br /&gt;
&lt;br /&gt;
Also, the code is easier to read and maintain.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
The whole thing looks like this:&lt;br /&gt;
&lt;br /&gt;
  01025    ! Dimension the Arrays&lt;br /&gt;
  01030    DIM color$(1)*1023,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*1023,colorcat(1)&lt;br /&gt;
  01050    DIM form$(1)*255&lt;br /&gt;
  02000 !&lt;br /&gt;
  02020 library &amp;quot;fileio.br&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$) ! Open the file&lt;br /&gt;
  05000 ! &lt;br /&gt;
  30120    read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore ! Read the file&lt;br /&gt;
  30180    LET ColorCode$=color$(co_Code) !:&lt;br /&gt;
           LET ColorName$=color$(co_Name) ! Use the data by referincing it in the file arrays&lt;br /&gt;
  80000 !&lt;br /&gt;
  90000 ! Every program using fileio needs the following code&lt;br /&gt;
  99010  OPEN: ! ***** Function To Call Library Openfile And Generate Subs&lt;br /&gt;
  99020     def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths)&lt;br /&gt;
  99030        dim _FileIOSubs$(1)*800&lt;br /&gt;
  99040        let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$)&lt;br /&gt;
  99050        for Index=1 to udim(mat _FileIOSubs$) : execute (_FileIOSubs$(Index)) : next Index&lt;br /&gt;
  99060     fnend&lt;br /&gt;
&lt;br /&gt;
== File Layouts ==&lt;br /&gt;
Now lets inspect the anatomy of a properly formatted file layout. These should be placed in a subdirectory called filelay.&lt;br /&gt;
&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  X,              Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
&lt;br /&gt;
The first line contains the name of the Farm File, a unique string to prefix all of your subscript pointers, and the file version number. The subscript value is to ensure that the program knows the difference between the Farm File’s Farm Code, and the Route File’s Route Code. (One will be RT_CODE and the other is FM_CODE).  These are separated by a comma. Spacing does not matter, so adjust your spacing so that it looks nice.&lt;br /&gt;
&lt;br /&gt;
The Version number is used to determine when the data has changed, and an update needs to be made to your data file. Your file layouts should all start at version 0, and each time you want to make a change, you may increment this value by 1.&lt;br /&gt;
&lt;br /&gt;
Each time you open a file with the FILEIO library, it reads the file version number of the file on disk (using the BR version() function), and then it compares it to the version number in your file layout. If your file layout has a higher version number then your existing data file, then the library opens the backup of the file layout for the version of the data file that exists on disk. It makes a backup copy of the existing data file, and creates a new file with the proper version number. Then it reads your records one at a time, and copies all the data from the old file into the new file one field at a time. If a field is dropped from the file layout, that data gets lost. If fields are rearranged, the data is copied and saved in the new file in the new positions. If a new field is added, it starts out blank (or 0).&lt;br /&gt;
&lt;br /&gt;
If you look in the filelay folder, you will notice a version folder. This contains several files ending with a number. For example you may see a color.0, and a color.1 file.&lt;br /&gt;
&lt;br /&gt;
If you run the fnopen function and it can not find your data file (usually because this is a new file and it hasn’t been created yet), &#039;&#039;the library will automatically create your file,&#039;&#039; based on the information you give in the first part of the file layout.&lt;br /&gt;
&lt;br /&gt;
Also, whenever you make changes to your file layout, the function library will automatically update the data files on disk for you. It does this by renaming the old file, creating a new one with the new version number, and then copying the data from the old one to the new one a record at a time.&lt;br /&gt;
&lt;br /&gt;
Any time it creates a file, or updates the file on disk, it creates a backup of the file &#039;&#039;layout&#039;&#039;. The first time you run a program that tries to read your new data file, it will create the data file for you and make a backup of the layout, and if the number in your file layout is 0, then it will create, for example, a filelay\version\price.0 file, a backup of your file layout that the library uses to figure out what has changed the next time you try to update the file.&lt;br /&gt;
&lt;br /&gt;
If you wish to make any changes to this data file, first you increment the version number, (in this case make the 0 into a 1). Then change the file layout all you want. You may rearrange fields, add new fields, add or remove keys, or change the record length.&lt;br /&gt;
&lt;br /&gt;
The only step necessary for having your data files updated is to increment the version number every time you make a change to the file layout.&lt;br /&gt;
&lt;br /&gt;
You may make any changes you like to the file layouts, but do not change the names of your existing subscripts. If you change the subscript name, not only will all the programs that reference that subscript be broken, but additionally, the routine will not understand that you are changing the name. It will think you are dropping the old field and adding a new field and any data stored in this location will be lost when the file is updated.&lt;br /&gt;
&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
&lt;br /&gt;
The second line contains the name of the first key, and a definition telling what the key is based on. These are separated by a comma. The key definition is made up of each of the subscript names in this file that form the keyfields for the file. When the library is called to open a file, if the file does not exist, or if it needs to be updated, a new one will be created. The function will read these subscript names that form your key definitions, and it will calculate the proper key position (KPS=) and length (KLN=) values. Then the create routine will use this information with the Index command to create the new key files.&lt;br /&gt;
&lt;br /&gt;
  price.key, ITEM&lt;br /&gt;
  price.ky2, FARM&lt;br /&gt;
  price.ky3, ITEM/FARM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
&lt;br /&gt;
Notice that the third key is based on three different fields. These are separated by a “/”. It is important that you use a “/” to separate your keys when you are building a key out of more then one field, because the function uses this “/” to help it make the proper BR syntax for defining complex key fields.&lt;br /&gt;
&lt;br /&gt;
The file can have as many keys as you want. The function will keep parsing key file names until it reaches the next part of the layout. It opens any OutIn files with all keys so that any changes you may make to the data stored on disk will be properly reflected in all the key files.&lt;br /&gt;
&lt;br /&gt;
The optional RECL= Parameter is read and used whenever a new file is created or an old one is updated. If it is not specified, the record length is calculated from the fields in the layout.&lt;br /&gt;
&lt;br /&gt;
  ===================================================&lt;br /&gt;
&lt;br /&gt;
The next line in the file is skipped by the parsing routine, and its purpose is to make the file layouts more readable to a programmer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
&lt;br /&gt;
Following the file and key structure, the fields are defined. There are three parameters on each field definition line, and you make one line for each field in your file layout. The first parameter is the subscript name that you will use in your program to refer to this data element. Place a $ at the end of the subscript name for all string elements. Don’t place anything at the end of the subscript name for numeric elements. Note that each of these names will be prefixed by the second parameter of the very first line of this layout. &lt;br /&gt;
&lt;br /&gt;
The second parameter is the description. This description is for the benefit of the programmer, so when the programmer is reading the file layouts, (s)he can tell which field does what. The spaces are ignored, so you may include as many spaces as you wish to make the layout look good. It does seem like good general guidelines would be to limit your layout lines to 255 characters and your descriptions to 80. &lt;br /&gt;
&lt;br /&gt;
The description is also used by the built in DataCrawler, a program that reads any of your data files and displays the entire contents in raw form in a listview. The Descriptions become the headings for each column in the listview. &lt;br /&gt;
&lt;br /&gt;
Those descriptions are also used for the default captions for your fields if you use ScreenIO, a library for building GUI programs that itself builds off of fileio.&lt;br /&gt;
&lt;br /&gt;
The third parameter is the form statement, which is pretty straightforward. Any items with a form statement of type “X” will be ignored, except that the length will still be used to calculate the position on disk of all remaining fields in the record. The library will take X fields into consideration when building the form statement, but not at any other time.&lt;br /&gt;
&lt;br /&gt;
The fourth parameter is optionally a [[#Support for Dates|Disk Date Format]]. You can specify DATE(Julian) if you&#039;re storing your dates in Julian format on disk. Or you can specify DATE(cymd) or DATE(ymd) or DATE(mdy) or any other valid date spec here, and FileIO will treat this field like a date.&lt;br /&gt;
&lt;br /&gt;
Your programs will still have to unpack it for you, fileio can&#039;t do that because fileio doesn&#039;t read the file for you.&lt;br /&gt;
&lt;br /&gt;
However, the data crawler, the automatic updates, and screenIO, are all compatible with these dates specified in your file layout.&lt;br /&gt;
&lt;br /&gt;
If the fourth parameter is anything other then DATE(format), then its treated as a comment and ignored.&lt;br /&gt;
&lt;br /&gt;
The fifth and all later columns, if any, are treated as comments and ignored.&lt;br /&gt;
&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
Comment line text must begin with an exclamation point, but it may be indented. Comment lines may appear anywhere (vertically) and are ignored. &amp;lt;br&amp;gt;&lt;br /&gt;
Blank lines are ignored as well.&lt;br /&gt;
&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
After the last field definition, an &#039;&#039;optional&#039;&#039; #eof# line may be specified, in which case any lines after that will be ignored. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  DUMMY,          Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
&lt;br /&gt;
And that’s all there is to it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Support for Dates ===&lt;br /&gt;
As of V2.48, file layouts support dates in any storage formats on disk. Whether you store your dates in Julian or in YMD or MDY or any other format, specify so in the 4th column of your file layouts, using the FileIO Date Keyword. ex: DATE(Julian) or DATE(YMD) or any other valid BR Date Format.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates0.png]]&lt;br /&gt;
&lt;br /&gt;
When this is specified, it enables the FileIO data exploration tool (Data Crawler) to display the dates in human readable format. This works for both Viewing, and for Editing.&lt;br /&gt;
&lt;br /&gt;
The new Date functionality also supports the File Layout Upgrade facility, allowing you to change the format of your dates on disk and FileIO will handle it automatically, upgrading the field to use the new date format for you.&lt;br /&gt;
&lt;br /&gt;
It works also for Exporting your data files to CSV, and is supported automatically in the FileIO functions that do those exports. It converts the dates on export to a standard format (Default: m/d/cy) that you can specify in your FileIO.Ini File.&lt;br /&gt;
&lt;br /&gt;
And it extends ScreenIO&#039;s date features to all date fields, no matter what format they&#039;re stored in. (Previously, ScreenIO&#039;s advanced date features only worked for dates stored in Julian on disk.)&lt;br /&gt;
&lt;br /&gt;
This update adds two new ini file options:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 DateFormatExport$=&#039;m/d/cy&#039;  ! Format of Dates when Exporting to CSV&lt;br /&gt;
 DateFormatDisplay$=&#039;m/d/cy&#039; ! Format of Dates when displaying in Data Crawler&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can use these to specify your preferred Date format for Viewing/Editing, and your preferred Date format for Exporting.&lt;br /&gt;
&lt;br /&gt;
Remember, you can see the full list of FileIO ini file options, by looking in the source code at the top of FileIO.&lt;br /&gt;
&lt;br /&gt;
There is a new optional parameter for all layout reading functions, mat NDateSpec$ and mat SDateSpec$ which correspond with the other arrays, to let you know which fields are date fields, so that you can develop routines in your programs to automatically pack and unpack the dates.&lt;br /&gt;
&lt;br /&gt;
Important Note: Using FileIO, the reading of the data file is still done directly in your programs. So this does not change how your existing programs work. It does not unpack the dates for you in your programs. You still have to do all that.&lt;br /&gt;
&lt;br /&gt;
For this reason, upgrading to the new Date processing will not break any of your current code.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tips ===&lt;br /&gt;
&lt;br /&gt;
When you&#039;re making new layouts, a missing comma can cause FileIO to parse the layout wrong and give you errors. Here are a couple tips to help ensure your layouts are error free before using them in your programs.&lt;br /&gt;
&lt;br /&gt;
*Use the Data Crawler to test your layout. The data crawler is the simplest way to test your new layout without writing any code. It opens it and accesses the file in a very simple and straight forward manor to help identify any errors in the layout that you might have.&lt;br /&gt;
&lt;br /&gt;
*If you have trouble with the form statement, you can&#039;t see whats in it because FileIO uses CForm$ to compile your form statement to make your programs run faster. But here&#039;s a way to tell what the original form statement was that FileIO generated when it put the strings first and numbers last in your program: Open the file in the Data Crawler. When you get an error, type &amp;quot;Print FormStatement$&amp;quot; to see the original form statement.&lt;br /&gt;
&lt;br /&gt;
This works even if your file is working fine. Any time the file is opened with the data crawler, you can press CTRL-A and then type PRINT FormStatement$ and it will print out the uncompiled form statement for the file.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
Now that you have your file layouts defined, you have access to several powerful utilities right out of the box using Fileio. Additionally, several more utilities are available as [[#FileIO_Add-on_Packages|Add-Ons]], including our most popular development tool [[Screenio|ScreenIO]]. You can read more about them in their section below.&lt;br /&gt;
&lt;br /&gt;
But for now, lets take a look at some of the wonderful free utilities that come built into Fileio.&lt;br /&gt;
&lt;br /&gt;
Some of these utilities are accessible from your code via library functions, but the primary way you access any of them is by simply loading the FileIO Library and running it directly.&lt;br /&gt;
&lt;br /&gt;
=== DataCrawler ===&lt;br /&gt;
The data crawler is the original utility of FileIO. This utility shows you first a list of all data files allowing you to select one.&lt;br /&gt;
&lt;br /&gt;
Select a data file and press enter, and FileIO will then display a listview containing all the data in the data file. This list is sized based on the size of your main BR window (window 0) automatically to take up the full size available to it, so if you want to see more, try [[Open Window|opening window 0]] larger before running FileIO.&lt;br /&gt;
&lt;br /&gt;
At the top of the window is a filter box, and you can type anything you want in there and click &amp;quot;Refresh&amp;quot; and it will reread the data file, shortening the list to show only those records that match (case insensitive) what you have typed.&lt;br /&gt;
&lt;br /&gt;
If you have ScreenIO installed, then FileIO&#039;s data crawler will take advantage of the included Animation Engine in ScreenIO to animate a loading window while the listview is displaying. If you don&#039;t have ScreenIO then FileIO will simply load the listview.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want to wait for the entire file to load, press ESC to stop the load process.&lt;br /&gt;
&lt;br /&gt;
If the file is empty, FileIO will display a message box letting you know.&lt;br /&gt;
&lt;br /&gt;
This tool is very useful for sorting out data errors. It will allow you to look inside any data file you have a layout for and directly view the data there.&lt;br /&gt;
&lt;br /&gt;
At the bottom of the Data Crawler are several buttons. There&#039;s a Jump button that repositions the file by a key you specify and then loads the list with the data from that key on down to the end of the file.&lt;br /&gt;
&lt;br /&gt;
There is a &amp;quot;Columns&amp;quot; button which you can use to decide which columns should show up on the listview. Fewer columns means faster loading so sometimes for large files I press ESC immediately when the file first starts loading to cancel the load. Then I click &amp;quot;Columns&amp;quot; and check only the columns I want to see. Finally I press the &amp;quot;Refresh&amp;quot; button to trigger it to read the file again and this time it loads much faster then before.&lt;br /&gt;
&lt;br /&gt;
Next you&#039;ll find an Export button which starts the process for exporting a file to CSV. You can read more on that in the next section. And next to that is a Quit button.&lt;br /&gt;
&lt;br /&gt;
In this example, we loaded the file &amp;quot;Read Only&amp;quot; so it put everything in a listview. But there are times when its useful to fix data errors this way too, especially during development. So if you want to directly edit your data file, on the first page select the file you want to edit and instead of pressing &amp;quot;Enter&amp;quot; or clicking &amp;quot;View&amp;quot;, this time press &amp;quot;F5&amp;quot;. F5 is the secret Edit button that loads a data file into a grid instead.&lt;br /&gt;
&lt;br /&gt;
You can use the grid to change records, delete them or add them, and in addition to the buttons listed above, it also has an &amp;quot;Import&amp;quot; button for importing a CSV file into this data file.&lt;br /&gt;
&lt;br /&gt;
Any changes you make to the data file are not saved until you click the &amp;quot;Save&amp;quot; button (which also only appears when you&#039;re in Edit mode).&lt;br /&gt;
&lt;br /&gt;
In the 01/2015 release of FileIO, each records rec # is displayed in the listview, to aid in debugging bad data problems.&lt;br /&gt;
&lt;br /&gt;
==== Debugging Tip ====&lt;br /&gt;
Any time you&#039;re viewing a file layout in the Data Crawler, you can see the Uncompiled Form Statement by pressing CTRL-A to get to an ATTN prompt, and then entering the command:&lt;br /&gt;
&lt;br /&gt;
  print FormStatement$&lt;br /&gt;
&lt;br /&gt;
and it will print out the original form statement.&lt;br /&gt;
&lt;br /&gt;
==== Another Debugging Tip ====&lt;br /&gt;
&lt;br /&gt;
The FileIO Datacrawler ignores records that it cannot read. This is to allow for data files that have multiple record layouts in one data file. You make a custom layout for each record type and the data crawler shows just the records that match that type in the file.&lt;br /&gt;
&lt;br /&gt;
However that becomes a problem when you&#039;re making a layout to work with an existing data file. Error 726 indicates that something minor in the file layout doesn&#039;t match the data on the disk, but these errors are ignored so you might see either an empty data file, or a data file with some records missing. If that happens, you need to see the missing records in order to figure out what is wrong with your layout. &#039;&#039;&#039;&#039;&#039;It&#039;s very important that you don&#039;t try to use a file layout that isn&#039;t quite working right. Make sure your layout works and can read every record of a file that it should read before using it.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To see the records that could not be read in a file, run the data crawler on the layout, then press CTRL-A to get an ATTN prompt. From there, enter the command&lt;br /&gt;
&lt;br /&gt;
  print mat BadRead$&lt;br /&gt;
&lt;br /&gt;
and it will print all the records that were ignored because the file layout didn&#039;t match them. It prints out the raw data from the file.&lt;br /&gt;
&lt;br /&gt;
==== Function Access to use Data Crawler in your programs ====&lt;br /&gt;
You can use the data crawler in your own programs by using one of the following functions:&lt;br /&gt;
* [[#fnDataCrawler|fnDataCrawler]] - Open a Listview showing the data file&lt;br /&gt;
* [[#fnDataEdit|fnDataEdit]] - Display the data in an editable grid&lt;br /&gt;
* [[#fnShowData|fnShowData]] - This function does the same thing as the above two, but with many many more options allowing you to customize exactly what appears and exactly what they&#039;re allowed to change.&lt;br /&gt;
&lt;br /&gt;
Note: its not recommended to allow your customers to use the data crawler to access your data files directly. There&#039;s no way to specify validations or do anything complicated, so unless you&#039;re careful, there are lots of ways your customers could use this tool to do damage to your data files. It is a programmer tool only.&lt;br /&gt;
&lt;br /&gt;
If you do decide to use it for your end users, be careful how you implement it.&lt;br /&gt;
&lt;br /&gt;
=== Import/Export to CSV ===&lt;br /&gt;
&lt;br /&gt;
You can use FileIO to export your data files to CSV or import from CSV into your data file. To do this, you want to run the data crawler and select the file layout you&#039;re looking for. Then, view it (or press F5 to edit if you want to import something). Click on the Export button and it will ask you to select a file. Once that is selected it will ask a couple other simple questions, and when you&#039;ve specified the options to your satisfaction, click the Export! button. A new CSV file will be created.&lt;br /&gt;
&lt;br /&gt;
Import is even more simple. To import, you must be in Edit mode (press F5 to select the file instead of the enter key) and then simply select the Import button. It will ask you again to choose the file, and then it will ask you if it should update all files by Record Number (if record number is recorded in the CSV file) or by Key (if the file has keys) or to just Add all information to the file. Select what you want and press Import and the CSV file is added to the BR data file.&lt;br /&gt;
&lt;br /&gt;
==== Function Access to Import/Export from your programs ====&lt;br /&gt;
&lt;br /&gt;
You can use the following functions to call the Import and Export functionality from your code.&lt;br /&gt;
&lt;br /&gt;
*[[#fnCSVImport|fnCSVImport]]&lt;br /&gt;
*[[#fnCSVExport|fnCSVExport]]&lt;br /&gt;
&lt;br /&gt;
These functions are intended to give you the ability to use our functionality to write your own import and export routines for your customers, because its not a good idea to let your customers run the Data Crawler.&lt;br /&gt;
&lt;br /&gt;
=== Generate Layout Wizard ===&lt;br /&gt;
&lt;br /&gt;
There is also a Generate Layout Wizard utility in FileIO. This utility is there to help you build your file layouts. It is designed to work with a certain style of BR programming that was common in the 80s and 90s. So if your software is written in a style that opens the file directly, and reads/writes the data to a long series of individual variables, the Generate Layout Wizard is for you.&lt;br /&gt;
&lt;br /&gt;
To use it, start by running FileIO. Then, don&#039;t select a layout - instead, click on the &amp;quot;Generate Layout&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
You&#039;ll see a screen with a bunch of large text boxes, a small grid, and some buttons.&lt;br /&gt;
&lt;br /&gt;
The first thing you want to do is select the &amp;quot;Browse&amp;quot; button and then select a .wb or .br file that contains a program that reads or writes Most of the File.&lt;br /&gt;
&lt;br /&gt;
When you select one, press the Scan All button and it fileio will search the whole program looking first for all the open strings. It will take the file that is opened the most times and then search for all read statements to that file. It will look for the longest read statement and then find the Form statement associated with that Read statement, and any DIM statements for any variables used.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t like the file its chosen, click the &amp;quot;Open Scratch Pad&amp;quot; button to open the temp work file it uses into the program of your choice (I use myEdit for BRS files). Simply select all the open statements for the file you DO want to build off of, then click the Paste button to paste those open statements into the &amp;quot;Open String&amp;quot; list. After that click &amp;quot;Clear All&amp;quot; to erase what it did on the first search and then click &amp;quot;Scan All&amp;quot; again to rescan the program using this new data file.&lt;br /&gt;
&lt;br /&gt;
You may have to help it a bit, but once it has a proper matching open statement, read statement, form statement and dim statements for any arrays used, press the &amp;quot;Generate Layout&amp;quot; button and it will build a layout for that file.&lt;br /&gt;
&lt;br /&gt;
Finally, load the layout it built and clean up anything if you want, and consider adding better descriptions for each of the fields that you know (as it will use the variable names for both the subscripts AND descriptions in the layout).&lt;br /&gt;
&lt;br /&gt;
When you&#039;re all done, click &amp;quot;Done&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Functions to Generate Layouts from your code ====&lt;br /&gt;
&lt;br /&gt;
* [[#fnGenerateLayout_.26_fnWriteLayout|fnGenerateLayout]]&lt;br /&gt;
* [[#fnGenerateLayout_.26_fnWriteLayout|fnWriteLayout]]&lt;br /&gt;
&lt;br /&gt;
=== Code Templates ===&lt;br /&gt;
&lt;br /&gt;
One more tool FileIO has to help is the ability to generate code based on your file layouts.&lt;br /&gt;
&lt;br /&gt;
Run FileIO and this time select a file layout and press &amp;quot;Generate Code&amp;quot;. A window will pop up listing all the &amp;quot;Code Templates&amp;quot; that are available. Select one (and then select a key if it asks you - some templates require extra info). It looks like nothing happened, but the code you generated is now in your clip board. Paste it somewhere and take a look at it!&lt;br /&gt;
&lt;br /&gt;
Code Templates help us to standardize our ways of doing things, which eventually leads to more and more powerful tools we can use. Code Templates also help ensure we use cleaner code by doing some of the busy-work of writing clean code for us.&lt;br /&gt;
&lt;br /&gt;
==== Writing Code Templates ====&lt;br /&gt;
FileIO ships with several basic code templates. If you want to add your own, take a look in the filelay\templates folder (configurable in fileio.ini) and look at basic.brs. Copy it to your own program and then modify it to have your own code templates in it. Write me at gabriel.bakker@gmail.com with any questions. I want to help.&lt;br /&gt;
&lt;br /&gt;
And if you write good code templates, its easy to share them with the BR community. Anyone can download your templates and place them in this folder and they&#039;ll instantly be available for use.&lt;br /&gt;
&lt;br /&gt;
== FileIO Function Reference ==&lt;br /&gt;
&#039;&#039;The FileIO Library contains a number of other useful functions.&#039;&#039; The following functions are available and you are welcome to use them:&lt;br /&gt;
&lt;br /&gt;
=== Primary Functions ===&lt;br /&gt;
&lt;br /&gt;
==== fnOpen ====&lt;br /&gt;
fnOpen is the primary function that opens a file, and it’s used like so:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, DontSortSubs, Path$*255, Mat Descr$, Mat FieldWidths, SupressPrompt, IgnoreErrors, SuppressLog)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note that all of the parameters after MAT Form$ are optional. If you need to specify a parameter in the middle of the optional parameter group, just list zeroes and empty strings for the intervening unused parameters. &lt;br /&gt;
&lt;br /&gt;
*FileName$ - The filename of the file layout for the file you’re reading.&lt;br /&gt;
*MAT F$ - The array that will be used to hold the string data for the file.&lt;br /&gt;
*MAT F – The array that will hold the numeric data for the file.&lt;br /&gt;
*MAT Form$ - An array of form statements.&lt;br /&gt;
*InputOnly – 1 means open for input only. 0 means open for OutIn and open every key file associated with the given data file (this is because all key files need to be open for the keys to be updated on an output) (defaults to 0). Files opened for input process considerably faster than files opened for output. Furthermore when files are opened for input only, alternate key files are &#039;&#039;not&#039;&#039; opened.&lt;br /&gt;
*KeyNum – This tells the function of which key to return the file handle (defaults to 1).&lt;br /&gt;
*DontSortSubs – The function by default, when compiling the Form statement, will sort the string and numeric subs in order to allow for reading the data into an array, and this parameter would turn this functionality off. However, if you are trying to read your data without reading it into an array, you are missing out on some serious efficiencies. You should normally leave this option turned off (0). This is a totally unsupported feature, and should always be set to 0, if it is specified at all.&lt;br /&gt;
*Path$ - The path to your data files. This optional parameter can be passed in by the calling function. It is prefixed to the beginning of the paths given in the file layout files. It is useful when your data files can be in different locations depending on the state of your program.&lt;br /&gt;
*mat Description$ - This optional parameter provides a way to read the description for each field from the original file layout. If the parameter is not provided, no description data will be returned. &lt;br /&gt;
*mat Fieldwidths – This optional parameter will return an array of the calculated display field widths. This number will always be at least large enough to contain the data for this field.&lt;br /&gt;
*SuppressPrompt - This optional parameter can be used to suppress the prompt normally given when fileIO creates a file. It can have three values. A value of 0, the default, uses the setting stored in your FileIO fnSettings routine to determine weather or not to prompt on Creation of a new file. A nonzero value always suppresses the prompt. A value of 1 indicates never to create a file if the file doesn&#039;t exist. A value of 2 automatically creates the file if the file doesn&#039;t exist.&lt;br /&gt;
*IgnoreErrors - Normally when fileio opens a data file, if there are errors trying to open the file, it prints them out to the debug console and pauses so that you can try to find out whats going wrong. If you specify 1 for &amp;quot;IgnoreErrors&amp;quot; it will cause Fileio to log those errors instead, and continue loading your program. This will result in the fnOpen file function returning Zero instead of the opened file number, so if you use IgnoreErrors, you need to test to make sure that fnOpen returned a file number before you try to access the file.&lt;br /&gt;
*SuppressLog - this optional parameter can be used to suppress writing to the log file for this one specific open statement. I use it for files that will be opened all the time, for example, the menu data file on one of my customers systems. Without this boolean parameter, his log file is quickly filled up with useless information any time his employees look at his menu. I specify this optional parameter to suppress logging anything about the menu file so that I can more easily find the actual programs they&#039;ve used when looking in the logfile.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Note: When using fnOpenFile, you really want to call your local function fnOpen, which in turn calls fnOpenFile for you.&#039;&#039;&#039;&#039;&#039;  FnOpenFile is for internal use only.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  Let FFILE=FNOPEN(“FARM”,MAT FARM$,MAT FARM,MAT FORM$,0,2)&lt;br /&gt;
  Let RFILE=FNOPEN(“ROUTE”,MAT ROUTE$,MAT ROUTE,MAT FORM$,1,3)&lt;br /&gt;
  Let CFILE=FNOPEN(“CUSTOMER”,MAT CUSTOMER$,MAT CUSTOMER,MAT FORM$)&lt;br /&gt;
&lt;br /&gt;
assuming:&lt;br /&gt;
  farm.dat has 3 keys: farm.ky1, farm.ky2, farm.ky3&lt;br /&gt;
  route.dat has 4 keys: route.ky1 … route.ky4&lt;br /&gt;
  customer.dat has 2 keys: customer.ky1, customer.ky2&lt;br /&gt;
&lt;br /&gt;
This will perform the following opens and set the following variables:&lt;br /&gt;
&lt;br /&gt;
  OPEN #1: “Name=Farm.Dat, kfname=farm.ky2”,internal,outin,keyed&lt;br /&gt;
  OPEN #2: “Name=Farm.Dat, kfname=farm.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #3: “Name=Farm.Dat, kfname=farm.ky3”,internal,outin,keyed&lt;br /&gt;
  OPEN #4: “Name=Route.Dat, kfname=route.ky3”,internal,input,keyed&lt;br /&gt;
  OPEN #5: “Name=Customer.Dat,kfname=customer.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #6: “Name=Customer.Dat,kfname=customer.ky2”,internal,outin,keyed&lt;br /&gt;
  LET FFILE=1&lt;br /&gt;
  LET RFILE=4&lt;br /&gt;
  LET CFILE=5&lt;br /&gt;
&lt;br /&gt;
This will also resize the arrays, set the form statement, and create all the subscripts to make accessing the data clear and simple, as in the above example. The KEYNUM parameter is where you list the key file you would like to use for reading and writing. The extra keys are opened to ensure that all keys get updated properly when the file is changed.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  DIM FORM$(1),PRICE$(1)*255,PRICE(1),&lt;br /&gt;
  DIM DESCRIPTION$(1)*80,FIELDWIDTHS(1)&lt;br /&gt;
&lt;br /&gt;
  Let PRICEFILE=FNOPEN(“PRICE”,MAT PRICE$,MAT PRICE,MAT FORM$,0,2,0,&amp;quot;&amp;quot;,MAT DESCRIPTION$)&lt;br /&gt;
&lt;br /&gt;
Assuming the Price File layout (filelay\price) contains:&lt;br /&gt;
&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  DUMMY,          Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
 &lt;br /&gt;
This will perform the following opens and set the following variables:&lt;br /&gt;
&lt;br /&gt;
  OPEN #1: “Name=Price.Dat, kfname=Price.ky2”,internal,outin,keyed&lt;br /&gt;
  OPEN #2: “Name=Price.Dat, kfname=Price.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #3: “Name=Price.Dat, kfname=Price.ky3”,internal,outin,keyed&lt;br /&gt;
  let PRICEFILE=1&lt;br /&gt;
  let PR_FARM=1&lt;br /&gt;
  let PR_ITEM=2&lt;br /&gt;
  let PR_GRADE=3&lt;br /&gt;
  let PR_DESCR=4&lt;br /&gt;
  let PR_PRICE=1&lt;br /&gt;
  let PR_COST=2&lt;br /&gt;
  let PR_XOPRICE=3&lt;br /&gt;
  let PR_XOCOST=4&lt;br /&gt;
  let PR_MOPRICE=5&lt;br /&gt;
  let PR_MOCOST=6&lt;br /&gt;
  let PR_VOPRICE=7&lt;br /&gt;
  let PR_VOCOST=8&lt;br /&gt;
  MAT FORM$(1)&lt;br /&gt;
  MAT PRICE$(4)&lt;br /&gt;
  MAT PRICE(8)&lt;br /&gt;
  MAT DESCRIPTION$(12)&lt;br /&gt;
  MAT FIELDWIDTHS(12)&lt;br /&gt;
  let FORM$(1)=CFORM$(”form C 4,C 4,C 4,POS 74,C 30,POS 50,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2”)&lt;br /&gt;
  let Description$(1)= “Farm Code (or blank)”&lt;br /&gt;
  let Description$(2) = “Item Code”&lt;br /&gt;
  let Description$(3) = “Quality”&lt;br /&gt;
  let Description$(4) = “Description of Price Rule”&lt;br /&gt;
  let Description$(5) = “Default Price”&lt;br /&gt;
  let Description$(6) = “Default Cost”&lt;br /&gt;
  let Description$(7) = “Default Christmas Price”&lt;br /&gt;
  let Description$(8) = “Default Christmas Cost”&lt;br /&gt;
  let Description$(9) = “Default Mothers D Price”&lt;br /&gt;
  let Description$(10) = “Default Mothers D Cost”&lt;br /&gt;
  let Description$(11) = “Default Valentine Price”&lt;br /&gt;
  let Description$(12) = “Default Valentine Cost”&lt;br /&gt;
  let FieldWidths(1) = 4&lt;br /&gt;
  let FieldWidths(2) = 4&lt;br /&gt;
  let FieldWidths(3) = 4&lt;br /&gt;
  let FieldWidths(4) = 30&lt;br /&gt;
  let FieldWidths(5) = 8&lt;br /&gt;
  let FieldWidths(6) = 8&lt;br /&gt;
  let FieldWidths(7) = 8&lt;br /&gt;
  let FieldWidths(8) = 8&lt;br /&gt;
  let FieldWidths(9) = 8&lt;br /&gt;
  let FieldWidths(10) = 8&lt;br /&gt;
  let FieldWidths(11) = 8&lt;br /&gt;
  let FieldWidths(12) = 8&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
There are a few things I’d like to point out about the example above. First, you will notice that the form statement jumps around to put all the strings first, and then the numbers last. This is why it has a “POS 74, C 30,POS 50”. Then notice that the subscripts for the string variables are 1 .. 4, and the subscripts for the numbers are 1 .. 8. Finally, the order of the Description and FieldWidth fields also match the sorted positioning of the Form Statement.&lt;br /&gt;
&lt;br /&gt;
The reason that we sort our form statements is so that BR will allow us to read the file into arrays by saying:&lt;br /&gt;
&lt;br /&gt;
  Read #pricefile, using form$(pricefile) : mat price$, mat price&lt;br /&gt;
&lt;br /&gt;
Without resorting, the above statement would give a conversion error as BR attempted to put the PR_PRICE field inside mat price$(4). However, because we have reordered the form statement, we are able to read them safely into two arrays, and then we will be able to use the values without caring what position they are in the file, by simply saying PRICE$(PR_DESCRIPTION) when we want the description, and PRICE(PR_PRICE) when we want the pr_Price field.&lt;br /&gt;
&lt;br /&gt;
Another thing you may notice about the above example is that it gives the calculated display length for the numeric fields as 8, when on the disk (and in the file layout) they are listed as BH 3.2. The reason for this is the program looks at the BH 3, and figures that a number that takes up 3 bytes on disk has a potential maximum size of 256**3 or 16,777,216, and therefore will need up to 8 characters of screen display space to view. &lt;br /&gt;
&lt;br /&gt;
Finally, note that any field with a form statement of X is ignored by the library, except that the blank space is used when building the FORM statement.&lt;br /&gt;
&lt;br /&gt;
==== fnCloseFile ====&lt;br /&gt;
This function will close the specified file number and all keys that were opened with the file.  The purpose of this function is to facilitate the closing of the extra keys that are opened when you open a file for OutIn with the library. There is no need to use this for files opened for input because it is easier to just close the file directly. Secondary keys are not opened by FileIO for files opened for input only. &lt;br /&gt;
&lt;br /&gt;
You must give the function the name of the file layout. It uses this information to determine how many keys were opened, and how many it must therefore close. &lt;br /&gt;
&lt;br /&gt;
Then it basically starts at the file number you gave it, and closes the next X files that were opened with the same file name as this, where X is the number of keys associated with this file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCloseFile(filenumber,filelay$;path$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FileNumber – The filenumber of the file you are trying to close.&lt;br /&gt;
*FileLay$ - The name of the file layout for this file. This is used to determine how many keys the file would have been opened with and therefore how many we now need to close.&lt;br /&gt;
*Path$ - Optional Alternate Path. Use to close files that were opened using the open file&#039;s optional alternate path parameter.&lt;br /&gt;
&lt;br /&gt;
==== fnGetFileNumber ====&lt;br /&gt;
FnGetFileNumber is a simple function to find a valid unused file handle. If you use this function in all of your programs, they will become much more portable, as you will never have to worry about your file handles fighting with each other. The function will return 0 if no free file number was found (but with 999 of them available now, I have never seen it happen).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnGetFileNumber(;X,Count)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*X – This optional parameter will specify where to start looking.&lt;br /&gt;
*Count - This optional parameter will specify how many file numbers to find in a row. If count is 3, then fnGetFileNumber will return the first filenumber in the first gap of three unused file numbers that it finds.&lt;br /&gt;
&lt;br /&gt;
=== File Reading Helper Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions perform various useful calculations to aid in interacting with data files when you&#039;re using fileio.&lt;br /&gt;
&lt;br /&gt;
==== fnBuildKey$ ====&lt;br /&gt;
This function will return the key for a given record in a data file. It actually reads the file layout and builds the key to match the layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnBuildKey$(Layout$, Mat F$, Mat F; Keynum)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the name of the data file to build the key for.&lt;br /&gt;
*Mat F$ - the string array of the file object&lt;br /&gt;
*Mat F - the numeric array of the file object&lt;br /&gt;
*KeyNum - This optional parameter specifies which of the key files in the given layout the key should be built for.&lt;br /&gt;
&lt;br /&gt;
To use this, you want some code like in the following example:&lt;br /&gt;
&lt;br /&gt;
  mat customer$=(&amp;quot;&amp;quot;) : mat Customer=(0)&lt;br /&gt;
  let customer$(cu_name)=CustName$&lt;br /&gt;
  let customer$(cu_phone)=CustPhone$&lt;br /&gt;
  read #customer, using form$(Customer), key=fnBuildKey$(&amp;quot;customer&amp;quot;,mat Customer$,mat Customer,2) : mat Customer$, mat Customer nokey KeyNotFound&lt;br /&gt;
  ! The above code assumes that the second key of the Customer file is based on the Name and Phone fields.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
By using this logic you are able to avoid directly specifying the key in your code - which means that even if the key changes in the future, as long as your code specifies enough information, it will still find the correct key. In our example, even if we dropped the phone number from the key in the future, or even if we expand the length of the Customer Name field, our code would still work and fnBuildKey$ would still build the correct key without us having to look at or change our code again.&lt;br /&gt;
&lt;br /&gt;
This kind of reasoning is central to the fileio system, which, when implemented properly, ensures that you can change your data files in any way you need to in the future, without breaking your existing programs.&lt;br /&gt;
&lt;br /&gt;
==== fnUniqueKey ====&lt;br /&gt;
This function tests to see if a given key is unique to the specified file. This function is very useful for situations where you need to ensure that the user-entered key is unique.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnUniqueKey(Fl,key$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file number of the opened file.&lt;br /&gt;
*Key$ - This is the key to test. If this key is the key for a preexisting record in the file, the function will return false. If this key can not be found in the file, the function will return true.&lt;br /&gt;
&lt;br /&gt;
==== fnMakeUniqueKey$ ====&lt;br /&gt;
This function generates a unique key for a given file. This is useful if you do not care what the key is, but it needs to be unique. I use this function in situations where the user never needs to know what the given key is. &lt;br /&gt;
&lt;br /&gt;
This function reads the key length for the given file. Then it returns a string that is the right length, which is generated by counting in binary until a key is found that does not appear in the file. The first key found for a 4 byte key field would be chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0). If that key was already in use in the file, the function would return chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(1). If that one was also in use, it would then try chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(2), and so on until it found one that wasn’t in use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnMakeUniqueKey$(fl)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – This is the file number of the opened file for the desired key.&lt;br /&gt;
&lt;br /&gt;
==== fnKey$ ====&lt;br /&gt;
This function formats the key for the given file number. All it does is ensure the key is the correct length. You should use fnBuildKey$ instead to properly build the correct key for the record you want to read.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnKey$(FileNumber, Key$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileNumber - the file number we are formatting the key for&lt;br /&gt;
*Key$ - the key we are trying to format.&lt;br /&gt;
&lt;br /&gt;
==== fnNotInFile ====&lt;br /&gt;
This function will determine if a non-key element in a line is unique. It works almost exactly like fnUniqueKey specified above, except that it allows you to enter the subscript value of the element you are checking for uniqueness. You can use this to look for uniqueness in any field, not just in the key field. Additionally, the search engine used by this function looks for a partial match, and will only return true if the given string is not found anywhere in the specified element for the given file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnNotInFile(string$*100,filename$,sub)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - Value to check for uniqueness in this file.&lt;br /&gt;
*Filename$ - This is the name of the file layout of the file you want to check. This file does not have to be open in order for you to search it, because the function will open it for you.&lt;br /&gt;
*Sub – This is the subscript value of the element you are checking.&lt;br /&gt;
&lt;br /&gt;
==== fnSortKeys ====&lt;br /&gt;
This function takes an array of Primary Keys indicating records in the data file, and resorts it into the order you would have expected using one of the other keys for your data file.&lt;br /&gt;
&lt;br /&gt;
For example: Lets say you had a customer file, and the first key was Customer Code and the second key was Customer Last Name. This function would take an array of Customer Codes and sort it into Last Name order.&lt;br /&gt;
&lt;br /&gt;
This function requires the file to already be opened (which is usually the case when you have an array of keys from that file).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnSortKeys(mat Keys$,Layout$,DataFile,mat F$,mat F,mat Form$;KeyNum)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Keys$ - the array of keys. These keys are based on whatever key the file was opened with in DataFile.&lt;br /&gt;
*Layout$ - the file layout for the file.&lt;br /&gt;
*DataFile - the open file number matching the key file that matches mat Keys$.&lt;br /&gt;
*mat F$ - array sized to hold the strings from the data file. This is the array you get back from fnOpen.&lt;br /&gt;
*mat F - array sized to hold the numerics from the data file. This is the array you get back from fnOpen.&lt;br /&gt;
*mat Form$ - array of form statements, that you get back from fnOpen.&lt;br /&gt;
*KeyNum - This is the key that we&#039;ll sort based on. If not given, the first key listed in the layout is assumed.&lt;br /&gt;
&lt;br /&gt;
=== File Reading Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions actually read information from your data file and return it. These functions can be used to simplify the logic in your programs for many common tasks.&lt;br /&gt;
&lt;br /&gt;
==== fnReadAllKeys ====&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record into (a) dynamically dimensioned array(s). For example, I could tell it to give me the Inventory Code for every inventory item in my database in one array, while placing the Inventory Description (name) for each item into the corresponding position in another array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadAllKeys(Fl,mat f$,mat f,mat fm$,sub1,mat out1$;sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – The file handle for the already opened file in question.&lt;br /&gt;
*mat F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array&lt;br /&gt;
*mat out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*mat out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If I wanted to implement the above example, I would say:&lt;br /&gt;
&lt;br /&gt;
  FnReadAllKeys(InventFile,mat Invent$,mat Invent,mat Form$,IN_Code,mat InvtList$,IN_Name,mat InvtNames$)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnReadMatchingKeys ====&lt;br /&gt;
&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record where the key matches the specified key into (a) dynamically dimensioned array(s). This function is the same as the above function except this one will filter the results, returning only those records where the key matches the specified key.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadMatchingKeys(Fl,mat f$,mat f,mat fm$,key$,keysub,sub1,mat out1$;sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*mat F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Key$ - Only records where the key field matches key$ will be returned.&lt;br /&gt;
*Keysub – This tells the function which element is the key element for this particular file number.&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*mat out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnReadAllNewKeys ====&lt;br /&gt;
&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record that isn’t already there into (a) dynamically dimensioned array(s). This function is the same as the above function, except this one will filter the results returning only those records that don’t already exist in the array (eliminating duplicates).&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;FnReadAllNewKeys(Fl,mat f$,mat f,mat fm$,sub1,mat out1$; dont_reset,sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*MAT F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Dont_reset – By default the array will clear the contents of the arrays that are passed in. This Boolean flag will instruct the function to not empty the passed in arrays.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*MAT out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
==== fnReadFilterKeys ====&lt;br /&gt;
&lt;br /&gt;
This function by Mikhail Zheleznov is a modification of the above functions. Like its predecessors, it reads an entire file, populating the specified arrays with data from all or some of the records in the file. The given subscripts specify which fields to return from each record. The key given specifies search criteria for the records. The filter specifies filtering criteria that can be preformed on the data before it is returned. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadFilterKeys(Fl,Mat F$,Mat F,Mat Fm$,Key$,Keyfld,Sub1,Mat Out1$;Filter$,Filter_Sub,Readlarger,Sub2,Mat Out2$, Sub3, Mat Out3$, Sub4,Mat Out4$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*MAT F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Key$ - The key to search for in the read statements&lt;br /&gt;
*Keyfld – the subscript of the key field in the data file. This must match the key field specified in the data file otherwise the function won’t work.&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Filter$ – This optional parameter identifies matches to search for in the records. It works in conjunction with Filter_Sub&lt;br /&gt;
*Filter_Sub – This parameter specifies which field to look for in the records for matches to Filter$. Only records which have Filter$ in the specified field will be returned.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*MAT out2$ - Array in which to return the second (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
*Sub3 – Subscript of the element to return in the third array. This is optional. If it is specified, you must give MAT out3$, or BR will return an error.&lt;br /&gt;
*MAT out3$ - Array in which to return the third (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub3 is given (non-zero). This parameter will not be used if Sub3 is not given or is given as 0.&lt;br /&gt;
*Sub4 – Subscript of the element to return in the fourth array. This is optional. If it is specified, you must give MAT out4$, or BR will return an error.&lt;br /&gt;
*mat out4$ - Array in which to return the fourth (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub4 is given (non-zero). This parameter will not be used if Sub4 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
This function was written by Mikhail Zheleznov for the fileIO library.&lt;br /&gt;
&lt;br /&gt;
==== fnReadDescription$ ====&lt;br /&gt;
&#039;&#039;fnReadDescription$(Fl,Subscript,key$,mat F$,mat F,mat Form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – File Handle for file to use (Route File).&lt;br /&gt;
*Subscript – Index of field in record to use (should be taken from file layout) (RT_NAME, which should equal 2 after opening routefile (unless we change the file layout later)).&lt;br /&gt;
*key$ - Item that should match a key in this file somewhere (in this case it is the route code from the farm record).&lt;br /&gt;
*mat F$ &amp;amp; mat F - Work Variables to hold a file record from the file we are reading they have to be dimensioned properly, which is why we use our colorcat$ and our colorcat for these parameters.&lt;br /&gt;
*mat Form$ - This will need to be our array of form statements, so the function can read the file properly.&lt;br /&gt;
&lt;br /&gt;
Lets take a look at how this function works:&lt;br /&gt;
&lt;br /&gt;
In the example program I used above, I am reading the Color File to get details about each color. The color file contains a colorcat code field, but I want to display the colorcat description. The colorcat file contains a few details about a color category, and it is indexed based on colorcat code:&lt;br /&gt;
&lt;br /&gt;
  route.dat, RT_&lt;br /&gt;
  route.key, CODE&lt;br /&gt;
  recl=512&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE,           Routing Code,                C    6&lt;br /&gt;
  NAME,           Routing Name Description,    C   30&lt;br /&gt;
  MOFT,           T/A/C (truck/air/courier),   C    1&lt;br /&gt;
  SHIPPINGDAY,    Day of Week for Shipping,    C    7&lt;br /&gt;
&lt;br /&gt;
Now, as you know, in the above example, we have already opened the ColorCat File, and we have opened and read a Color record.&lt;br /&gt;
 &lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  30120       read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore&lt;br /&gt;
  30180       LET ccode$=color$(CO_CODE) !:&lt;br /&gt;
              LET Name$=color$(CO_NAME)&lt;br /&gt;
&lt;br /&gt;
Now all that’s left to do is to take the Color File’s ColorCat code and use it to look up the ColorCat File’s description.&lt;br /&gt;
&lt;br /&gt;
  30190 LET ColorCat$ = fnReadDescription$(ColorCatFile, CC_NAME, Color$(CO_CATEGORY),&lt;br /&gt;
    mat ColorCat$, mat ColorCat, mat form$)&lt;br /&gt;
&lt;br /&gt;
==== fnReadUnopenedDescription$ ====&lt;br /&gt;
This function accomplishes the same thing as fnReadDescription except that it opens the data file for you. It is slower then FnReadDescription$, but it is easier to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadUnopenedDescription$(Layout$,key$*255;Field)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are reading&lt;br /&gt;
*key$ - the value of the key field in the record to be read&lt;br /&gt;
*Field - the element of the data file to return. If not given, this defaults to 2, so sometimes it is a good idea to design your data files so that string field number two is a descriptive field, like Name or Description.&lt;br /&gt;
&lt;br /&gt;
This function only works on the first key file for each data file. This function is a convenience function but it is slow because it opens the file and closes it for each call. Opening a file is one of the most time consuming program operations.&lt;br /&gt;
&lt;br /&gt;
==== fnReadNumber ====&lt;br /&gt;
&lt;br /&gt;
fnReadNumber does the same thing that ReadDescription does except it reads a numeric field instead of a description.&lt;br /&gt;
&lt;br /&gt;
Lets take a look at how this function works:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadNumber(Fl,subscript,key$,mat F$,mat F,mat fm$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – File Handle for file to use (Route File).&lt;br /&gt;
*Subscript – Index of field in record to use (should be taken from file layout).&lt;br /&gt;
*Key$ - Item that should match a key in this file somewhere.&lt;br /&gt;
*mat F$ &amp;amp; mat F - Work Variables to hold a file record from the file we are reading. They have to be dimensioned properly by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat Fm$ - This will need to be our array of form statements, so the function can read the file properly.&lt;br /&gt;
&lt;br /&gt;
==== fnReadUnopenedNumber ====&lt;br /&gt;
This function accomplishes the same thing as fnReadNumber except that it opens the data file for you. It is slower then FnReadNumber, but it is easier to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadUnopenedNumber(Layout$,key$*255;Field)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are reading&lt;br /&gt;
*key$ - the key of the record to be read&lt;br /&gt;
*Field - the element of the data file to return. If not given, this defaults to 2, so sometimes it is a good idea to design your data files so that string field number two is a descriptive field, like Name or Description.&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelativeDescription$ ====&lt;br /&gt;
This function is the same as fnReadDescription$ but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelativeDescription$(FileNumber,SubscriptToRead,RecordNumber,mat F$,mat F,mat form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Filenumber - The file number of the open data file&lt;br /&gt;
*SubscriptToRead - The subscript to read&lt;br /&gt;
*RecordNumber - the Record number to read&lt;br /&gt;
*mat F$ and mat F - the arrays to hold the data. They must match the dimensions and should be set with [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat form$ - the forms array is also set by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelUnopenedDescription$ ====&lt;br /&gt;
This is the same as ReadUnopenedDescription$ but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelUnopenedDescription(Layout$,RecordNumber;Field)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*RecordNumber - the record to read&lt;br /&gt;
*Field - the field subscript to read&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelativeNumber ====&lt;br /&gt;
This is the same as fnReadNumber but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelativeNumber(FileNumber,SubscriptToRead,RecordNumber,mat F$,mat f,mat Form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Filenumber - The file number of the open data file&lt;br /&gt;
*SubscriptToRead - The subscript to read&lt;br /&gt;
*RecordNumber - the Record number to read&lt;br /&gt;
*mat F$ and mat F - the arrays to hold the data. They must match the dimensions and should be set with [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat form$ - the forms array is also set by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelUnopenedNumber ====&lt;br /&gt;
This is the same as fnReadUnopenedNumber but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelUnopenedNumber(LayoutName$,RecordNumber;Field)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*RecordNumber - the record to read&lt;br /&gt;
*Field - the field subscript to read&lt;br /&gt;
&lt;br /&gt;
==== fnReadRecordWhere$ ====&lt;br /&gt;
This function returns the record where the given element matches the given value. It does not depend on any key files, and it can be used to locate a record based on any element. However, it loops through the entire data file to do this and it could be a bit slow for large data files. This function opens the file for you, so the file does not have to be already opened.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadRecordWhere$(Layout$,SearchSub,SearchKey$*255,ReturnSub)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are searching&lt;br /&gt;
*SearchSub - Subscript of the element to look in&lt;br /&gt;
*SearchKey$ - The value we are looking for&lt;br /&gt;
*ReturnSub - Subscript of the element to return&lt;br /&gt;
&lt;br /&gt;
=== FileIO Utility Functions ===&lt;br /&gt;
==== fnDataCrawler ====&lt;br /&gt;
This function launches the Data Crawler as a function, so you can make your own programs link to it. Special thanks to Mikhail Zheleznov for turning the DataCrawler into a library function.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDataCrawler(Layout$;SRow$,SCol$,Rows$,Cols$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnDataEdit ====&lt;br /&gt;
This function is the same as fnDataCrawler only it opens a Grid for editing.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDataCrawler(Layout$;SRow$,SCol$,Rows$,Cols$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnShowData ====&lt;br /&gt;
&lt;br /&gt;
This function builds a list or a grid in a floating window that is tied to a data file. It uses the same function that the datacrawler uses, but its much more customizable. All other datacrawler functions are just wrappers for this one.&lt;br /&gt;
&lt;br /&gt;
The first parameter is the only required parameter.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;def library fnShowData(FileLay$;Edit,sRow,sCol,Rows,Cols,KeyNumber,Caption$*127,Path$*255,KeyMatch$*255,SearchMatch$*255,CallingProgram$*255,mat Records,mat IncludeCols$,mat IncludeUI$,mat ColumnDescription$,mat ColumnWidths,mat ColumnForms$,DisplayField$*80,mat FilterFields$,mat FilterForm$,mat FilterCompare$,mat FilterCaption$,mat FilterDefaults$,mat FilterKey)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileLay$ - the file layout you want to display&lt;br /&gt;
*Edit - 1 for Edit (Grid) and 0 for View (Listview)&lt;br /&gt;
*sRow, sCol - the start position. if not given, its centered. If given but out of bounds, they&#039;ll be automatically adjusted to fit the grid on the screen.&lt;br /&gt;
*Rows, Cols - the size. If not given, defaults to fullscreen. If given but not big enough to fit the UI elements you request, they&#039;re automatically adjusted to fit everthing.&lt;br /&gt;
*KeyNumber - the Key to use when reading the data, used with other parameters. If not given, the file is read Relative for faster performance. Required if KeyMatch$ is given.&lt;br /&gt;
*Caption$ - the Caption to display, defaults to FileIO&#039;s Datacrawler&lt;br /&gt;
*Path$ - Alternate path to use for data files (Prepended to the name found in the layout)&lt;br /&gt;
*KeyMatch$ - Show only records that match this key. You can use Partial Keys. If this parameter is given, you must also give KeyNumber (above).&lt;br /&gt;
*SearchMatch$ - Show only records that contain this substring in them anywhere&lt;br /&gt;
*CallingProgram$ - used for logging purposes, pass in the system function Program$&lt;br /&gt;
*mat Records - Show only these records in the Grid. Use it to control exactly what the user sees.&lt;br /&gt;
*mat IncludeCols$ - Show only these columns. These column names must match the subscript names from the file layout.&lt;br /&gt;
*mat IncludeUI$ - Which UI Options to show. Build this array with one element for each optional UI element to include. Explanations of UI elements follow:&lt;br /&gt;
**&amp;quot;ColumnsButton&amp;quot; - adds a Select Columns button that the user can use to modify which columns appear on the list.&lt;br /&gt;
**&amp;quot;ExportButton&amp;quot; - adds an Export to CSV button that exports the data to a CSV file.&lt;br /&gt;
**&amp;quot;ImportButton&amp;quot; - adds an Import from CSV button that imports from the CSV file.&lt;br /&gt;
**&amp;quot;AddButton&amp;quot; - adds a button that can be used to add records to the data file.&lt;br /&gt;
**&amp;quot;SaveButton&amp;quot; - adds a button allowing the user to save changes&lt;br /&gt;
**&amp;quot;DeleteButton&amp;quot; - adds a button allowing the user to delete a row&lt;br /&gt;
**&amp;quot;KeyButton&amp;quot; - adds a button allowing the user to jump to a specified position by key or by record number (depending on if the file is opened keyed or not)&lt;br /&gt;
**&amp;quot;QuitButton&amp;quot; - adds a Quit button to the screen (the Esc key also quits)&lt;br /&gt;
**&amp;quot;Search&amp;quot; - adds a case insensitive search box to the screen.&lt;br /&gt;
**&amp;quot;Border&amp;quot; - adds a border around the screen&lt;br /&gt;
**&amp;quot;Caption&amp;quot; - adds a caption. (If you specify a caption, this is automatically turned on. If you don&#039;t specify a caption but turn on caption here, then FileIO uses the default FileIO data crawler caption.&lt;br /&gt;
**&amp;quot;Recl&amp;quot; - adds the Recl to the caption&lt;br /&gt;
**&amp;quot;Position&amp;quot; - adds the positions to the field descriptions in the column headings.&lt;br /&gt;
*mat ColumnDescription$ - Show these captions. If blank, use the descriptions from the layout&lt;br /&gt;
*mat ColumnWidths - Use these widths for the data, if not given, calculate from the file layout&lt;br /&gt;
*mat ColumnForms$ - Display Format for the data, including DATE and FMT and PIC&lt;br /&gt;
*mat DisplayField$ - Counter Field to display on the Loading Window. If its a field with an associated DATE ColumnForms$ value, that column form will be used when displaying the Counter Field. It can be any of the following:&lt;br /&gt;
**REC - this will display the current &amp;quot;REC/LREC&amp;quot; data in the loading window.&lt;br /&gt;
**READCOUNT - this will display the &amp;quot;Record Count / LREC&amp;quot; in the loading window.&lt;br /&gt;
**FINDCOUNT - this will display the number of records that match the current search criteria by itself in the loading window.&lt;br /&gt;
**A Field Name - one of your field names will display that field value in the loading window&lt;br /&gt;
**A string literal - anything else will display as a string in the loading window, so you could put something like &amp;quot;Loading, please wait&amp;quot; here and it will display.&lt;br /&gt;
*mat FilterFields$ - Contains the subscript of the field to compare to&lt;br /&gt;
*mat FilterForm$ - Contains the format of the field to compare to&lt;br /&gt;
*mat FilterCompare$ - Contains the comparison type (&amp;quot;&amp;lt;&amp;gt;&amp;quot; or &amp;quot;&amp;gt;&amp;quot; or &amp;quot;=&amp;quot; or &amp;quot;&amp;gt;=&amp;quot; or &amp;quot;*&amp;quot;) (* means do a substring search)&lt;br /&gt;
*mat FilterCaption$ - The caption for the filter box&lt;br /&gt;
*mat FilterDefaults$ - The default value for the filter information&lt;br /&gt;
*mat FilterKey - The action to use when filtering the data this way (0 means simple exclude, 1 means start here, -1 means stop here)&lt;br /&gt;
**The final five arrays can be used to add user filter boxes to the data grid. You need one element in each array for every custom user filter box on the screen.&lt;br /&gt;
&lt;br /&gt;
==== fnCSVImport ====&lt;br /&gt;
&lt;br /&gt;
This function calls the FileIO Import routine, the same one that you get from the Datacrawlers Import Button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCsvImport(Layout$*64;SuppressDialog,FileName$*300,ImportModeKey)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout to import into&lt;br /&gt;
*SupressDialog - 1 to Supress the Import Dialog&lt;br /&gt;
*FileName$ - the name of the CSV file (Required if Dialog is Suppressed)&lt;br /&gt;
*ImportModeKey - the Import Mode Key (Required if Dialog is Suppressed)&lt;br /&gt;
**-1 - Add all records to the file&lt;br /&gt;
**0 - Update by Record Number (The file must contain a RecNum column and it must be first)&lt;br /&gt;
**1+ - Any positive number means Update by that Key (as listed in the layout).&lt;br /&gt;
&lt;br /&gt;
==== fnCSVExport ====&lt;br /&gt;
&lt;br /&gt;
This function exports a data file to a CSV file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCsvExport(Layout$*64;SuppressDialog,Filename$*300,IncludeRecNums,KeyNumber,StartKey$,KeyMatch$,Startrec,mat Records,SearchMatch$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The File Layout to Export&lt;br /&gt;
*SuppressDialog - (1 to Suppress the Export Dialog, 0 to show it)&lt;br /&gt;
*Filename$ - the output file name (Required if SuppressDialog is 1)&lt;br /&gt;
*IncludeRecNums - Include a column with the Record Numbers in it&lt;br /&gt;
*KeyNumber - Use this key when reading the data for export&lt;br /&gt;
*StartKey$ - Start with the record that matches StartKey$&lt;br /&gt;
*KeyMatch$ - Export only the record(s) that match KeyMatch$&lt;br /&gt;
*StartRec - Start with this Record Number&lt;br /&gt;
*mat Records - Export only these records&lt;br /&gt;
*SearchMatch$ - Export only records containing this search string anywhere in them&lt;br /&gt;
&lt;br /&gt;
==== fnGenerateLayout &amp;amp; fnWriteLayout ====&lt;br /&gt;
&lt;br /&gt;
This function calls on the Generate File Layout Wizard to generate and save the layout indicated by the parameters you give it. You must give it the same valid parameters that you would have come up with if you worked through the layout wizard the normal way, by running FileIO directly and choosing &amp;quot;Generate Layout&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can also bypass the automatic parsing and generate a layout by specifying all the data directly and using fnWriteLayout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnGenerateLayout(mat OpenStrings$, ReadString$*999, FormString$*20000, DimString$*999; DisplayFile)&#039;&#039;&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat OpenString$ - array of all the open strings for the given file from one of your old programs.&lt;br /&gt;
*mat ReadString$ - solid read statement from one of your old programs reading the entire record, (or at least everything you want in the layout).&lt;br /&gt;
*mat FormString$ - the form statement that goes with the ReadString$ (practice using the Generate Layout Wizard the normal way for details)&lt;br /&gt;
*mat DimString$ - the string containing Dim statements for each array mentioned in ReadString$. We need this to know how big the arrays are.&lt;br /&gt;
*DisplayFile - if True (1), it will Display the new layout in notepad when its done creating it. If false (0), it will simply create the file.&lt;br /&gt;
&lt;br /&gt;
fnGenerateLayout takes all the above information and parses it into a layout, then calls fnWriteLayout to actually write the layout.&lt;br /&gt;
&lt;br /&gt;
If you already know the information you want to put in the layout, its more direct to call fnWriteLayout below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnWriteLayout(Name$,FileName$*127,VER,PRE$,MAT KFNAME$,MAT KDESCRIPTION$,MAT SUBS$,MAT DESCR$,MAT FORM$;RECL,MAT EXTRA$,DISPLAYFILE)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Name$ - the name of the new layout&lt;br /&gt;
*FileName$*127 - the name of the data file&lt;br /&gt;
*Ver - the version of the data file&lt;br /&gt;
*Pre$ - the prefix to use for the data file&lt;br /&gt;
*mat KfName$ - array of all the keys for the file&lt;br /&gt;
*mat Kdescription$ - array of the subscripts that each key is based on&lt;br /&gt;
*mat Subs$ - the subscript for each field in the file&lt;br /&gt;
*mat Descr$ - the descriptions for each field in the file&lt;br /&gt;
*mat Form$ - the form specs for each field in the file&lt;br /&gt;
*Recl - (optional) the record length of the file&lt;br /&gt;
*mat Extra$ - (optional) Additonal Information for each field in the file, placed in the Comments column of the new layout. This column is ignored by standard fileio processing.&lt;br /&gt;
DisplayFile - if True, open the file in Notepad after it has been created.&lt;br /&gt;
&lt;br /&gt;
=== File System Utility Functions ===&lt;br /&gt;
These functions perform other tasks that aid with interacting with the file system.&lt;br /&gt;
&lt;br /&gt;
==== fnGetFileDateTime$ ====&lt;br /&gt;
This does a directory listing to determine the Last Modified Date and Time of the given file. You pass it a file name, not a file layout, and it can be used on any file. Its not limited to BR internal files.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let FileDate$=fnGetFileDateTime$(Filename$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnCopyFile ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCopyFile(FromFile$*255,ToFile$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FromFile$ - The file to copy.&lt;br /&gt;
*ToFile$ - The destination file name including path.&lt;br /&gt;
&lt;br /&gt;
This function copies any file, by opening it as an external file and reading and writing the data to the destination file. The advantage of this technique, over using the BR copy command, is this routine is more reliable when run on client server where you may be transferring large files from one side to the other over the internet.&lt;br /&gt;
&lt;br /&gt;
This fnCopyFile also has a progress bar that displays as the file is transferred, so the user knows your software is busy.&lt;br /&gt;
&lt;br /&gt;
This function works over Client Server. Under Client Server, specify @: at the beginning of your filename, to specify that the file is on the client. If the file is on the server, simply leave the @: off. See the chapter on [[Copy#Client_Server|using BR&#039;s copy command under Client Server]] for more details on the &amp;quot;@:&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This function&#039;s parameters and syntax are modeled off of the built in BR copy command, and like that one, this should work for local transfers, LAN transfers, or even internet transfers. This function will work better for internet transfers then the built in BR Copy Command, however. &lt;br /&gt;
&lt;br /&gt;
==== fnCopyDataFiles ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCopyDataFiles(DestinationFolder$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*DestinationFolder$ - the folder to copy your data files to.&lt;br /&gt;
&lt;br /&gt;
This function reads your file layouts and makes a copy of every data file (and key file) in your system to the destination folder, utilizing fnCopyFile above, for better performance and reliability when running over the internet, as well as a progress bar for each individual file.&lt;br /&gt;
&lt;br /&gt;
It also displays a listview while its copying so you can watch the progress while its transferring your data files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This can be used for making backups of your BR data, or for transferring the latest data onto a laptop for access to it while you&#039;re on the road away from the internet.&lt;br /&gt;
&lt;br /&gt;
==== fnReIndex ====&lt;br /&gt;
&lt;br /&gt;
This function reindexes a single data file&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReIndex(DataFile$*255;CallingProgram$*255,IndexNum,Path$*25)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Datafile$ - the file layout of the file to index&lt;br /&gt;
*CallingProgram$ - used for logging, pass Program$ in here&lt;br /&gt;
*IndexNum - The index to rebuild - if not given, rebuilds all indexes&lt;br /&gt;
*Path$ - the optional alternate path to use for rebuilding the data file.&lt;br /&gt;
&lt;br /&gt;
==== fnReIndexAllFiles ====&lt;br /&gt;
&lt;br /&gt;
This function reindexes all your data files. It doesn&#039;t require any parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReIndexAllFiles&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnUpdateFile ====&lt;br /&gt;
This function checks and Updates a data file if it needs to be updated, by opening and then closing the data file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnUpdateFile(FileLayout$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileLayout$ - The name of the file to update&lt;br /&gt;
&lt;br /&gt;
==== fnRemoveDeletes ====&lt;br /&gt;
&lt;br /&gt;
This function, written by Susan Smith, removes deleted records by copying the file with the -D option.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnRemoveDeletes(LayoutName$*255;Path$*255,CallingProgram$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*LayoutName$ - the file layout&lt;br /&gt;
*Path$ - Optional Alternate Path&lt;br /&gt;
*CallingPRogram$ - used for logging, pass Program$ in here&lt;br /&gt;
&lt;br /&gt;
=== Layout Interrogation ===&lt;br /&gt;
Layout interrogation functions are provided for convenience and to enable future dictionary changes without disrupting any programs that interrogate it.&lt;br /&gt;
&lt;br /&gt;
==== fnMakeSubProc ====&lt;br /&gt;
This function obtains the subscript assignments that were assigned by fnOpen according to the file layout. The fnMakeSubProc$ routine obtains the subscript assignments without actually opening the file. This is useful when a file record is passed as arrays into a library function in another program, or when you chained to another program and you need to know how to reach the data in the arrays without actually reopening the file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnMakeSubProc(filelay$;mat Subscripts$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FileLay$ - The name of the file layout from which to read the subscripts.&lt;br /&gt;
*mat Subscripts$ - If you give this optional array, fnMakeSubProc passes the subscripts back in this array rather then in the subs.$$$ file. This is much faster and helps avoid sharing conflicts.&lt;br /&gt;
&lt;br /&gt;
When this routine returns, you can set the subscripts in your program by executing every element of the Subscripts$ array in a for/next loop.&lt;br /&gt;
&lt;br /&gt;
If you did not pass in a subscripts array, then the a procedure file named subs.$$$ is created. If you proc that file, the proper subscripts will be set.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutArrays ====&lt;br /&gt;
This function reads the fields in a file layout into arrays. You call it like the following&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLayoutArrays(filelay$,&amp;amp;prefix$;mat SSubs$, mat NSubs$, mat SSpec$, mat NSpec$,mat SDescription$, mat NDescription$,Mat Spos,Mat Npos)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*filelay$ - the name of the layout to read&lt;br /&gt;
*prefix$ - the return value for the prefix for the file&lt;br /&gt;
*mat SSubs$ - the return value for all the string subscripts in the layout&lt;br /&gt;
*mat NSubs$ - the return value for the numeric subscripts in the layout&lt;br /&gt;
*mat SSpec$ - the return value for the string fields specs&lt;br /&gt;
*mat NSpec$ - the return value for the numeric fields specs&lt;br /&gt;
*mat SDescription$ - the return value for the Descriptions of the String Specs&lt;br /&gt;
*mat NDescription$ - the return value for the Descriptions of the Numeric Specs&lt;br /&gt;
*mat SPos - the return value for the starting positions of the String Specs&lt;br /&gt;
*mat NPos - the return value for the starting positions of the Numeric Specs&lt;br /&gt;
&lt;br /&gt;
This function call would read the fields from the layout in filelay$, and it would return the prefix to prefix$. The Subs would be returned in mat SSubs$ and mat NSubs$.&lt;br /&gt;
&lt;br /&gt;
The Spec statements are returned in mat SSpec$ and mat NSpec$ and the Descriptions are returned in mat SDescription$ and mat NDescription$. The start positions on disk of each element are returned in mat SPos and mat NPos.&lt;br /&gt;
&lt;br /&gt;
All the arrays are optional. If you don’t pass them the information they are supposed to record is simply not returned.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutHeader ====&lt;br /&gt;
This function reads the header for a given file layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLayoutHeader(Layoutname$*255;&amp;amp;Filename$,Mat Keys$,Mat KeyDescription$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*LayoutName$ - Name of the layout to read&lt;br /&gt;
*Filename$ - The file name read from the layout&lt;br /&gt;
*Mat Keys$ - Array to be populated with the list of keys for the file&lt;br /&gt;
*Mat KeyDescription$ - Key Description String returned from the file&lt;br /&gt;
&lt;br /&gt;
==== fnReadEntireLayout ====&lt;br /&gt;
This function reads the entire layout by calling fnReadLayoutHeader and fnReadLayoutArrays.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadEntireLayout(Layoutname$*255;&amp;amp;Filename$,&amp;amp;Prefix$,Mat Keys$,Mat KeyDescription$,Mat Ssubs$,Mat Nsubs$,Mat Sspec$,Mat Nspec$,Mat Sdescription$,Mat Ndescription$,Mat Spos,Mat Npos)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*LayoutName$ - Name of the layout to read&lt;br /&gt;
*Filename$ - The file name read from the layout&lt;br /&gt;
*prefix$ - the return value for the prefix for the file&lt;br /&gt;
*Mat Keys$ - Array to be populated with the list of keys for the file&lt;br /&gt;
*Mat KeyDescription$ - Key Description String returned from the file&lt;br /&gt;
*mat SSubs$ - the return value for all the string subscripts in the layout&lt;br /&gt;
*mat NSubs$ - the return value for the numeric subscripts in the layout&lt;br /&gt;
*mat SSpec$ - the return value for the string fields specs&lt;br /&gt;
*mat NSpec$ - the return value for the numeric fields specs&lt;br /&gt;
*mat SDescription$ - the return value for the Descriptions of the String Specs&lt;br /&gt;
*mat NDescription$ - the return value for the Descriptions of the Numeric Specs&lt;br /&gt;
*mat SPos - the return value for the starting positions of the String Specs&lt;br /&gt;
*mat NPos - the return value for the starting positions of the Numeric Specs&lt;br /&gt;
&lt;br /&gt;
==== fnReadSubs ====&lt;br /&gt;
This function reads the subscripts from a layout into Subs arrays.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadSubs(Layout$,mat SSubs$,mat NSubs$,&amp;amp;Prefix$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - the file layout name&lt;br /&gt;
*mat SSubs$ - the String Subscript Names&lt;br /&gt;
*mat NSubs$ - the Number Subscript Names&lt;br /&gt;
*Prefix$ - the files Prefix&lt;br /&gt;
&lt;br /&gt;
==== fnReadKeyFiles ====&lt;br /&gt;
This function reads the list of key files from the layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadKeyFiles(Layout$,mat Keys$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*mat Keys$ - output array, the keys are returned here.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayouts ====&lt;br /&gt;
This function reads the file layout folder and returns all the applicable layouts in the passed in array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadLayouts(mat Dirlist$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Mat Dirlist$ - After running the function, mat Dirlist$ will contain a list of all the file layouts that FileIO can find.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutPath$ ====&lt;br /&gt;
This function doesn&#039;t actually interrogate your layouts. Instead, it interrogates your settings and returns the path specified for your layout files. This would usually be &amp;quot;filelay\&amp;quot; but you can change it in [[#fnSettings|fileio.ini.]]&lt;br /&gt;
&lt;br /&gt;
It has no parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let Path$=fnReadLayoutPath$&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnDoesLayoutExist ====&lt;br /&gt;
This function returns true if the given file layout exists. It returns false if the layout does not exist.&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;FnDoesLayoutExist(layout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - Layout to test for&lt;br /&gt;
&lt;br /&gt;
==== fnReadForm$ (uncompiled) ====&lt;br /&gt;
Sometimes you need to know the original form statement that fileio is using to read your data file, most often when you&#039;re debugging your file layout, and you&#039;re getting some problem when reading the file. The form statement that fileio normally returns is compiled using CFORM$ to save space in the array, and to make the execution of your read statements faster. You can use this function to return the original form statement for the file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let FormStatement$=fnReadForm$*10000(FileLayout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remember to dimension FormStatement to something huge! fnReadForm$ can return up to 10,000 characters.&lt;br /&gt;
&lt;br /&gt;
==== fnReadFormAndSubs ====&lt;br /&gt;
&lt;br /&gt;
This function does the same as above but it also reads the subscripts from the file into an array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let fnReadFormAndSubs(Layout$,mat Subs$,&amp;amp;ReadForm$,&amp;amp;StringSize,&amp;amp;NumberSize)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note that unlike most of our functions, all the above parameters are required.&lt;br /&gt;
&lt;br /&gt;
The layout is the layout you&#039;re interrogating. The Array will be populated with the subscripts after the function. The ReadForm$ variable will be filled with the form statement for the file. Remember to dimension it large enough. StringSize and NumberSize will contain the number of string fields and numeric fields in the file.&lt;br /&gt;
&lt;br /&gt;
Mat Subs$ will be returned, strings first, numbers last, matching the form statement that is returned. So Subs$(1) is the first string subscript and Subs$(StringSize+1) is the first Numeric subscript.&lt;br /&gt;
&lt;br /&gt;
==== fnClearLayoutCache ====&lt;br /&gt;
&lt;br /&gt;
fnClearLayoutCash (v2.3+) clears out the cache of layout name and data to get realtime Updates to File Layouts.&lt;br /&gt;
&lt;br /&gt;
=== Other Useful Functions (non-layout related) ===&lt;br /&gt;
&lt;br /&gt;
==== fnAskCombo ====&lt;br /&gt;
&lt;br /&gt;
Opens a window with a combo box and returns the users selection.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnAskCombo$*255(mat Description$;Caption$*60,Default$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Description$ - contains the combo box choices&lt;br /&gt;
*Caption$ - contains the optional caption for the window&lt;br /&gt;
*Default$ - the text of the item in mat Description$ that you want to be selected by default&lt;br /&gt;
&lt;br /&gt;
==== fnSendEmail ====&lt;br /&gt;
&lt;br /&gt;
This function sends an email and an optional attachment to the email address specified.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnSendEmail(Emailaddress$*255,Message$*10000;Subject$*255,Invoicefile$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*EmailAddress$ - the Destination Email Address&lt;br /&gt;
*Message$ - the Message$ to send&lt;br /&gt;
*Subject$ - the subject&lt;br /&gt;
*InvoiceFile$ - the filename of a file to attach. This is the BR filename (the function automatically converts it to an OS Filename.)&lt;br /&gt;
&lt;br /&gt;
The function returns 1 when the email was sent successfully, or 0 if it wasn&#039;t sent successfully.&lt;br /&gt;
&lt;br /&gt;
In order to use this function, you must have the emailcfg file layout in your layouts folder and you must have a copy of SendEmail.exe which is free and can be downloaded from the internet. Both of these files are included with the latest update of fileio.&lt;br /&gt;
&lt;br /&gt;
You also have to configure fileio with the authentication information for your email server.&lt;br /&gt;
&lt;br /&gt;
To configure your email server, simply run FileIO to get the data crawler, then select the emailcfg file layout and press F5 to edit it. Add a row if the file is empty.&lt;br /&gt;
&lt;br /&gt;
Simply fill in the information the file is asking for in the appropriate fields and save the data, and then test sending an email to make sure it worked.&lt;br /&gt;
&lt;br /&gt;
==== fnClientEnv$ ====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a Windows Environment Variable on the client under Client Server.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnClientEnv$*255(EnvKey$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*EnvKey$ is the name of the Windows Environment Variable to check on the client.&lt;br /&gt;
&lt;br /&gt;
The function returns the value of the entered environment variable.&lt;br /&gt;
&lt;br /&gt;
==== fnEmpty &amp;amp; fnEmptyS ====&lt;br /&gt;
These functions are for testing optional arrays that may or may not have been passed into your function. BR will give an error if your code attempts to use an optional array that wasn&#039;t passed in, so you can use these functions to test if the user actually passed in the optional array or not.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnEmpty(mat Numeric)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnEmptyS(mat String$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  def fnSomeFunction(String$,mat Array$; mat OptionalArray)&lt;br /&gt;
     if ~fnEmpty(mat OptionalArray) then&lt;br /&gt;
        ! mat Optional array was given, process it here.&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
==== fnReadScreenSize ====&lt;br /&gt;
This function reads the screen size of the given window (or window 0 if a window wasn&#039;t passed.) This is useful for centering a window on the screen, or for making sure window 0 is big enough for the child window you&#039;re trying to create.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadScreenSize(&amp;amp;Rows,&amp;amp;Cols;ParentWindow)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The screen size is returned in the first two parameters, and the third parameter tells the function which window to interrogate. If not given, it assumes window 0.&lt;br /&gt;
&lt;br /&gt;
==== fnBuildProcFile ====&lt;br /&gt;
This function builds a proc file to be executed later. This function and the next simplify the process of executing code in a proc file. It can even be used to spawn a new session of BR.&lt;br /&gt;
&lt;br /&gt;
To use it, call fnBuildProcFile one or more times and specify some lines of code to execute.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnBuildProcFile(Command$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;load Program2$&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;run&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;system&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  let fnRunProcFile(1)&lt;br /&gt;
&lt;br /&gt;
==== fnRunProcFile ====&lt;br /&gt;
&lt;br /&gt;
This function spawns a new copy of BR and in it, runs the proc file that you&#039;ve previously built using fnBuildProcFile (above).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; fnRunProcFile(;NoWait) &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The optional parameter &amp;quot;NoWait&amp;quot; causes the other session to spawn and run in a new thread. If you don&#039;t specify NoWait, the current session pauses and waits for the other session to close before proceeding.&lt;br /&gt;
&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;load Program2$&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;run&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;system&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  let fnRunProcFile(1)&lt;br /&gt;
&lt;br /&gt;
==== fnLog &amp;amp; fnErrLog ====&lt;br /&gt;
These next two functions are functions to aid in logging. When you call either of these two functions, you give them a string that you wish to log. They will open the FileIO Log File and add a record to the end of it containing some user information such as login_name and session$, and the string that you specified. FnErrLog does the same thing as fnLog except it also logs the Error Number and the Line.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnLog(string$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - the Log Message&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnErrLog(String$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - the Log Message&lt;br /&gt;
&lt;br /&gt;
==== fnLogArray ====&lt;br /&gt;
&lt;br /&gt;
This function logs the given arrays to the log file, logging each field in the arrays. Its useful for recording, for example, an entire data record that is about to be written to a data file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnLogarray(mat F$,mat f;Message$*512,CallingProgram$*255)&#039;&#039;&lt;br /&gt;
The first two parameters, of course, are the array to log. The third parameter is an optional message to be recorded along with the array, and the fourth optional parameter is the CallingProgram$ to save in the log along with the message. (The CallingProgram$ parameter can usually be passed as the system function Program$)&lt;br /&gt;
&lt;br /&gt;
==== fnSetLogChanges ====&lt;br /&gt;
This function works in conjunction with the next function, and they&#039;re for recording just what changed in a data file. When the file is read, you call fnSetLogChanges and record the &amp;quot;before&amp;quot; picture of the file record.&lt;br /&gt;
&lt;br /&gt;
After changes have been made and saved back to disk, you can call fnLogChanges below to record the actual changes.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnSetLogChanges(mat F$,mat F)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnLogChanges ====&lt;br /&gt;
This function is the other half of the function above. It compares the given arrays with the ones set previously in the above function and checks for changes. Then it generates a log message recording information about just the items that changed.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnLogChanges(mat F$,mat F;Message$*1024,CallingProgram$*255,Layout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You need to pass in the same two arrays as before, but this time the modified versions of them.&lt;br /&gt;
&lt;br /&gt;
You can also optionally pass a 1024 byte log message to record with the log entry.&lt;br /&gt;
&lt;br /&gt;
CallingProgram$ again should be passed as the system internal function Program$.&lt;br /&gt;
&lt;br /&gt;
The final parameter allows the passing of a Layout$. If you pass a Layout$, that layout is read and the subscripts are used when making the log message of changes, so that its easier to read. If you pass a layout, it will identify the changed fields by name. If you don&#039;t it will identify those fields by relative position number.&lt;br /&gt;
&lt;br /&gt;
==== fnViewLogFile ====&lt;br /&gt;
All of the above functions store the information by default into a BR internal file defined in the filelay\logfile layout.&lt;br /&gt;
&lt;br /&gt;
The fnViewLog function uses fnShowData to call the Data Crawler to display the FileIO Log File in a searchable listview.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnViewLogFile&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnReadLockedUsers ====&lt;br /&gt;
&lt;br /&gt;
This function returns a list of all users using the locked data file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLockedUsers(mat Users$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Users$ - the list of users is returned here&lt;br /&gt;
&lt;br /&gt;
==== fnDisplayLength ====&lt;br /&gt;
This function calculates the display length of a field based on its form spec.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDisplayLength(Spec$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Spec - the Form Spec to return the display length of.&lt;br /&gt;
&lt;br /&gt;
==== fnLength ====&lt;br /&gt;
This function calculates the length on disk of a field based on its form spec.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnLength(Spec$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Spec$ - the Form Spec to return the display length of.&lt;br /&gt;
&lt;br /&gt;
== FileIO fnSettings (Global Settings Code) ==&lt;br /&gt;
&lt;br /&gt;
The FileIO library can be made to implement certain policies across the board.  These are established by creating a file called fileio.ini and typing statements like the following into it. This file is &amp;quot;PROCed&amp;quot;, so you don&#039;t want to put line numbers in it.&lt;br /&gt;
&lt;br /&gt;
Anything you don&#039;t specify in fileio.ini will take its default value, shown below. So you only need to specify the items that you want to be different.&lt;br /&gt;
&lt;br /&gt;
Note, for the boolean settings below, 1 denotes TRUE and 0 denotes FALSE.&lt;br /&gt;
&lt;br /&gt;
  let EnforceDupkeys=1                   ! Enforce that key number 1 is unique key&lt;br /&gt;
  let Defaultfilelayoutpath$=&amp;quot;filelay\&amp;quot;  ! Path To Your File Layouts&lt;br /&gt;
  let Promptonfilecreate=1               ! Ask User Before Creating New Files&lt;br /&gt;
  let Createlogfile=0                    ! Use Logging&lt;br /&gt;
  let StartFileNumber=1                  ! Set above 300 to avoid conflicts with legacy programs.&lt;br /&gt;
  let CheckIndex=0                       ! Automatically Verify Indexes (slow)&lt;br /&gt;
  let CompressColumns=0                  ! Shrink or Expand Columns in Data Crawler by Default&lt;br /&gt;
  let MaxColWidth=20                     ! Max Default Column Width in Data Crawler&lt;br /&gt;
  let LogLibrary$=&amp;quot;&amp;quot;                     ! Defaut Log Library, defaults to None&lt;br /&gt;
  let LogLayout$=&amp;quot;&amp;quot;                      ! Log file layout, defaults to Internal File&lt;br /&gt;
  let AnimateDatacrawler=1               ! Use ScreenIO Animation for Datacrawler&lt;br /&gt;
  let TemplatePath$=&amp;quot;filelay\template\&amp;quot;  ! Default Template Path&lt;br /&gt;
  let IgnoreLayouts$=&amp;quot;&amp;quot;                  ! List any Ignore Layouts here.&lt;br /&gt;
  let CloseFileSimple=0                  ! Use simple comparison for fnCloseFile&lt;br /&gt;
&lt;br /&gt;
==== EnforceDupkeys ====&lt;br /&gt;
&lt;br /&gt;
Turn on the EnforceDupkeys option to force that the first key listed in your file layouts is a unique key. FileIO will generate the standard BR error for Dupkeys when attempting to create indexes if it is not unique.&lt;br /&gt;
&lt;br /&gt;
==== DefaultFileLayoutPath$ ====&lt;br /&gt;
&lt;br /&gt;
Use the DefaultFileLayoutPath option to specify the path from your programs to your file layout folder. The default is &amp;quot;filelay\&amp;quot;. Use this setting if you want to place your file layouts in another folder from the default.&lt;br /&gt;
&lt;br /&gt;
==== PromptOnFileCreate ====&lt;br /&gt;
&lt;br /&gt;
Use the PromptOnFileCreate setting to cause FileIO to display a message box whenever it is attempting to create a new file. This happens during the automatic update procedure, as well as during any attempt to access a file that does not exist. This setting should be turned off in your live system, and only turned on for development purposes. If you use the message box to cancel creating of the new file, then the file is not created, and fileIO or your application will most likely give an error when you attempt to actually access the new file.&lt;br /&gt;
&lt;br /&gt;
It can be useful during development to make sure that you don&#039;t accidentally create the wrong files, due to an incorrectly specified path or a typeo in the filename in the layout file. However, in a live system, these things have already been tested, and you generally want the default behavior, because you don&#039;t want your users to have the ability to cancel the normal operation of FileIO.&lt;br /&gt;
&lt;br /&gt;
==== CreateLogFile ====&lt;br /&gt;
&lt;br /&gt;
Use this option to specify weather or not to use the FileIO log file. If it is turned on, a log file called FileIO.log in the current directory is created with entries listing all attempts to open a file, automatically update one, or automatically update your indexes.&lt;br /&gt;
&lt;br /&gt;
==== StartFileNumber ====&lt;br /&gt;
&lt;br /&gt;
Use this option to set the starting file number that the fnGetFileNumber and the fnOpen functions use to search for available file numbers. This is so that if you have certian reserved file numbers in your code, you can make sure that FileIO will not use those reserved file numbers, causing a conflict with your already existing programs. The default is 1, which is fine if your software does not have any reserved file numbers.&lt;br /&gt;
&lt;br /&gt;
The allowable BR file numbers are 1-200 and 300-999.&lt;br /&gt;
&lt;br /&gt;
==== CheckIndex ====&lt;br /&gt;
&lt;br /&gt;
This function is used for Partial FileIO Implementations. If all of your software uses FileIO then all of your indexes are kept automatically up to date by the FileIO library and BR&#039;s internal file processing systems. However, if some of your programs do not use FileIO, and you use the FileIO library to add a new index file that those other programs do not know about, then its possible for the additional index file to become out of date when the master file is updated by your other programs.&lt;br /&gt;
&lt;br /&gt;
Use this setting to cause FileIO to check the DateTime stamp on all your index files when opening a new file, and automatically update any indexes that may have potentially gotten out of date from other programs.&lt;br /&gt;
&lt;br /&gt;
This option slows down the processing of the fnOpen function, particularly when running under client server over the internet. If you know that every program in your application suite uses FileIO, and that any programs that do not use FileIO still properly update all the indexes that your data file uses, then you can safely leave this setting turned off, and optimize your performance when opening several files using the fileIO system.&lt;br /&gt;
&lt;br /&gt;
==== CompressColumns ====&lt;br /&gt;
This instructs the datacrawler to use smaller widths for small columns. If CompressColumns is false, the data crawler will make the column the width of the field or the width of the caption, whichever is wider. If CompressColumns is true, it will use the width of the field, not the caption.&lt;br /&gt;
&lt;br /&gt;
==== MaxColWidth ====&lt;br /&gt;
This limits the column width to a set amount. This is applied after CompressColumns above.&lt;br /&gt;
&lt;br /&gt;
==== LogLibrary$ ====&lt;br /&gt;
If a library is specified here, then fileio looks for a BR library with the specified name, and attempts to call a library function in it called fnFileIOLog that. This function should expect six parameters, which are Logstring$, Login_Name$, Session$, Days of Date$, Time$, and CallingProgram$, if LogLayout is also nonblank.&lt;br /&gt;
&lt;br /&gt;
If you specify a LogLibrary and LogLayout is blank, then it calls your function giving it only 1 parameter.&lt;br /&gt;
&lt;br /&gt;
It will call your function &#039;&#039;&#039;&#039;&#039;instead of&#039;&#039;&#039;&#039;&#039; the normal log file. Use this to implement your own logging functions however you want.&lt;br /&gt;
&lt;br /&gt;
==== LogLayout$ ====&lt;br /&gt;
Use this setting to specify an alternate file layout for an alternate file to do the logging in. Base the file layout for this file on the logfile we supply for you in the filelay folder. It should have at least those fields, which our log routine will automatically populate, but you can add other fields if you want (though you will need to manage them yourself).&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t specify LogLayout, the default filelay\logfile will be used. This will allow you to also use the fnViewLogFile function to access it.&lt;br /&gt;
&lt;br /&gt;
==== AnimateDataCrawler ====&lt;br /&gt;
The sister library [[ScreenIO]] has a feature that allows you to use an animation of a clock in your loading screens in your own programs. If you have [[ScreenIO]] then FileIO will automatically detect it and use it to display a loading animation while the data in the data crawler loads.&lt;br /&gt;
&lt;br /&gt;
Set AnimateDataCrawler to false (0) in your fileio.ini file to bypass the animations if you do have screenio but don&#039;t want to see the animations anyway.&lt;br /&gt;
&lt;br /&gt;
==== TemplatePath$ ====&lt;br /&gt;
This setting points to the folder that contains the code templates used by the Generate Code button on the main page of the Data Crawler.&lt;br /&gt;
&lt;br /&gt;
==== IgnoreLayouts$ ====&lt;br /&gt;
This is a comma delimited list of all layouts that you wish to suppress from appearing on the main page of the data crawler. You can still access these layouts with your code, but they won&#039;t be listed in the data crawler for you to access.&lt;br /&gt;
&lt;br /&gt;
Whatever you&#039;re using for a log layout, is automatically added to this list.&lt;br /&gt;
==== CloseFileSimple ====&lt;br /&gt;
The fnCloseFile function closes all the individual handles to a data file that was opened for output using multiple keys.&lt;br /&gt;
&lt;br /&gt;
For BR 4.18 and higher, we support a better algorithm for detecting which files are matches for a given opened file number.&lt;br /&gt;
&lt;br /&gt;
Set CloseFileSimple to true (1) to force it to check the old way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== FileIO Add-on Packages ==&lt;br /&gt;
&lt;br /&gt;
Many FileIO Add-on packages are currently in the works.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Library ===&lt;br /&gt;
&lt;br /&gt;
The [[ScreenIO Library]] is a sister library to the FileIO library. The ScreenIO library requires the FileIO library in order to run.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO library is a complete Rapid Application Design tool that enables you to implement custom screen functions anywhere in your exiting programs.&lt;br /&gt;
&lt;br /&gt;
If you call the ScreenIO Library as a function library, you call a function called fnFM and tell it which screen you wish to use. The ScreenIO library loads your user interface, loads your data files, and preforms all the file maintenance operations you have designed into your screens.&lt;br /&gt;
&lt;br /&gt;
You can find out the latest information about the ScreenIO library in the ScreenIO page.&lt;br /&gt;
&lt;br /&gt;
=== Audit BR ===&lt;br /&gt;
&lt;br /&gt;
The [[AuditBR|Audit BR]] developer tool makes a backup copy of your file layouts. Then you run some code you&#039;re trying to test, and finally, run Audit BR again, to get a report showing all the changes to any of your data files automatically.&lt;br /&gt;
&lt;br /&gt;
== What’s New (also described above) ==&lt;br /&gt;
=== 2018 ===&lt;br /&gt;
*Support for dates in any storage formats on disk (v2.48)&lt;br /&gt;
&lt;br /&gt;
=== 2015 ===&lt;br /&gt;
*Added Rec to display for fnShowData&lt;br /&gt;
*Added FormStatement$ for debugging of form statements inside fileio&lt;br /&gt;
*Added mat BadRead$ for debugging of 726 errors when making new layouts&lt;br /&gt;
*Fixed a bug causing crash when logging things from long program folders&lt;br /&gt;
*fnClientEnv$ - reads a Windows Environment variable on the client using the command shell&lt;br /&gt;
*fnAskCombo$ - added an optional parameter to set default selection.&lt;br /&gt;
&lt;br /&gt;
=== 2010 - 2014 ===&lt;br /&gt;
*FileIO now caches your file layouts in memory to make it much faster then before when opening the same data file in multiple programs.&lt;br /&gt;
*Generate Layout Wizard&lt;br /&gt;
*fnShowData&lt;br /&gt;
*Improved Logging&lt;br /&gt;
*fnViewLogFile&lt;br /&gt;
*Import/Export&lt;br /&gt;
*Import/Export by Function&lt;br /&gt;
*Many other speed increases&lt;br /&gt;
*if ScreenIO is present, Datacrawler uses the animation routines&lt;br /&gt;
*fnBuildProcFile &amp;amp; fnRunProcFile&lt;br /&gt;
*fnGenerateLayout &amp;amp; fnWriteLayout&lt;br /&gt;
*fnReadForm$&lt;br /&gt;
*fnReadFormAndSubs&lt;br /&gt;
*fnGetFileDateTime$&lt;br /&gt;
*fnReadLayoutPath$&lt;br /&gt;
*fnSortKeys&lt;br /&gt;
*fnSetLogChanges&lt;br /&gt;
*fnLogChanges&lt;br /&gt;
*fnLogArray&lt;br /&gt;
*fnReadScreenSize&lt;br /&gt;
*fnEmpty&lt;br /&gt;
*fnEmptyS&lt;br /&gt;
*Many other useful functions that were added to the documentation at earlier dates.&lt;br /&gt;
&lt;br /&gt;
=== Spring 2009 ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;New Functions:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The FileIO Library has been updated in Spring 2009 to provide several new functions:&lt;br /&gt;
&lt;br /&gt;
*fnReadRecordWhere&lt;br /&gt;
*fnKey$&lt;br /&gt;
*fnBuildKey$&lt;br /&gt;
*fnReadUnopenedDescription$&lt;br /&gt;
*fnUpdateFile&lt;br /&gt;
*fnDisplayLength&lt;br /&gt;
*fnLength&lt;br /&gt;
*fnReadLayoutHeader&lt;br /&gt;
*fnReadEntireLayout&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Speed Increases:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Thanks to the BR [[Profiler]], we have increased the speed of FileIO fnOpen function by ten times when running over a LAN and by 100 times when running over the internet using Client Server.&lt;br /&gt;
&lt;br /&gt;
In order to get the new Speed Upgrades, you will need to make sure that you use the latest copy of the [[#fnOpen_Function|fnOpen]] function in each one of your programs that use FileIO.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Network FileIO:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
This version of FileIO has been optimized to work better in network situations.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;FnSettings: &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
There are more configuration options in the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] routine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Automatic Update Speed Fix:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The automatic update proceedure has been made to run more then 100 times faster then before according to our benchmarking tests.&lt;br /&gt;
&lt;br /&gt;
=== Fall 2008 ===&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;DataCrawler Grid:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
By popular request we added a read/write version to the data crawler. This version works exactly the same as the datacrawler did before but it displays all the contents of your data files in a grid instead of a listview. &lt;br /&gt;
&lt;br /&gt;
When you run the fileIO library as a program, it launches a tool known as the [[#DataCrawler|DataCrawler]]. The DataCrawler shows a listview displaying all your layout files in it. If you select one, it builds another listview with all the data in your selected data file.&lt;br /&gt;
&lt;br /&gt;
If you are looking at the first list of all your file layouts, and you press F5, a grid will be build displaying all the data in your data files. You can change any of the records you like, and when you&#039;re done, your changes will be saved to the data file. Additionally, you can Add or Delete records using the buttons at the bottom. Any changes you make are not written to the disk until you click the &amp;quot;Save&amp;quot; button. If you press ESC (Cancel) the grid is closed and all changes you made sinse the last save are lost.&lt;br /&gt;
&lt;br /&gt;
This tool is for programmers only. Do not give your end users access to the DataCrawler.&lt;br /&gt;
&lt;br /&gt;
Use the DataCrawler at your own risk. Gabriel Bakker and Sage AX are not responsible for any harm that comes to your data files through the use of this or any other tools we offer.&lt;br /&gt;
&lt;br /&gt;
The DataCrawler is not designed to be used to maintain your data files. It can be used carefully to correct small things in your data files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Support for Nonstandard Paths:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Many BR Vendors keep different versions of the same data files in different locations. For example, sometimes a BR vendor will use a different Data folder to represent data for different Warehouses, or Customers. In cases like this it is necessary for your programs to specify the path to your data files. They may do so by specifying the optional &amp;quot;PATH&amp;quot; parameter to your data files. See the section [[#fnOpenFile]] for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Support for Nonstandard Layout Files Path:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Old versions of the fileIO library required you to place all your file layouts in a subfolder of your program directory called &amp;quot;filelay&amp;quot;. We have now changed the Fileio library to allow you to place your file layouts any place you want. The only requirement is that they are all together in one folder by themselves.&lt;br /&gt;
&lt;br /&gt;
If you use a nonstandard path in the fileIO library, it is necessary to make a change to the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] code in your copy of fileio.br.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Prompt on Create:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The FileIO library automatically creates any data files that it can&#039;t find. This was done to make it easier to deploy your finished programs - if you had any empty data files you could omit them from the packages and they would be created when they were needed, on the fly.&lt;br /&gt;
&lt;br /&gt;
The current version of the FileIO library contains the same ability. However, it prompts you before creating any data files. This helps to avoid bugs that happen from incorrectly specifying the path to your data files.&lt;br /&gt;
&lt;br /&gt;
However, if you do intend for your data files to be autocreated, then you probably don&#039;t want your end users to modify them. Therefore, you can use the PromptOnCreate setting in the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] code to specify. If this value is set to true, then the fileIO library will prompt you whenever it attempts to Autocreate a data file. If it is set to false, then the fileIO library will create the data files without prompting you, like it always did before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;fnSettings:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The newest version of the FileIO library supports some features that require you to specify Global Settings values. These are done by modifying the contents of the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] routine at the beginning of the fileIO library.&lt;br /&gt;
&lt;br /&gt;
=== Fall 2006 ===&lt;br /&gt;
Many improvements have been made in the FileIO library over the summer. This section is intended to acquaint you with the highlights of those changes. Most of these improvements were built from ideas generated during the discussion at the April conference.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Intermixed String and Numeric Specs:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The File Library has been expanded to allow the reading of data files that contain mixed string and numeric specs. This is to aid those of you who are planning on implementing the FileIO Library on existing data files which may not be organized with strings first and numbers second.&lt;br /&gt;
&lt;br /&gt;
The central idea of the FileIO Library is based upon the reading of your data files into a String and Numeric array. This will enable you to refer to the fields in your file by using a named subscript, saying F$(FM_NAME) to refer, for example, to the farm file’s name field. The advantage to this is that when you change the file layout, all your existing programs will not have to be modified, because they will only be looking at F$(FM_NAME). If the name field changes from the third string field to the fourth, the value of FM_NAME will also change, and you won’t have to worry about updating your data files.&lt;br /&gt;
&lt;br /&gt;
However, in order to support the reading of a data file with intermixed string and numeric specs, the generated form statement will actually calculate the position of any fields that are not in order, so that the file read statement will still return all string fields first (into your string array) and the numeric fields second (into your numeric array). You do not need to worry about this; the library does it for you. All you have to do is read your file and use the data values.&lt;br /&gt;
&lt;br /&gt;
The only thing that is required is making sure that all your string subscript names end with a “$”. This will tell the library that they are strings. Thank you, George, for this suggestion.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Versioning / Automatic Updates:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The file layouts have been expanded to contain a version number. This version number will be used to determine when a file needs to be updated. The version number is the third parameter in the file layout.&lt;br /&gt;
&lt;br /&gt;
Any time you wish to change your file layouts, simply increment this version number. Each time the library attempts to open a data file, the file’s version is checked and compared with the version in the file layout. If the file layout has been changed (if the version in the file layout is greater then the version in the file) then the file will be updated to the latest version. Depending on the file size this may take a couple of moments. A simple progress bar will be displayed on screen while this is happening. The progress bar will be displayed in its own window, so it should not affect anything your programs may have had on screen.&lt;br /&gt;
&lt;br /&gt;
The library uses the following procedure for updating a file. First, the file is copied to a backup file (prefixed by the letter ‘o’ for old). So color.dat would become ocolor.dat, and color.key would become ocolor.key. Then the new file is created and marked with the proper version number. (color.dat, color.key). The old file is opened in read-only mode, and the new file is opened for OutIn. The update routine actually reads through the old file layout, and one record at a time creates a new record, using the new file layout, with the same data, saving it to the new data file.&lt;br /&gt;
&lt;br /&gt;
When it is done upgrading, the progress bar window is closed, and the file is reopened in the fashion you described in your call to fnOpen, and flow returns to your program as though nothing unusual has happened.&lt;br /&gt;
&lt;br /&gt;
If an error occurs during processing, the routine will do what it can to roll your data files back to the previous version, but please make frequent backups of your data files anyway, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Error Checking – If there is a mistake in the file layout:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The routine attempts to discover the cause of the error in the case that one is encountered due to a missing file, a file sharing violation, or an invalid or corrupt file layout. If this should happen, the program is paused, and a text message is printed out explaining the most likely source for the error, including what part of the file layout, if any, may have caused the error.&lt;br /&gt;
&lt;br /&gt;
You may then examine the printed text, and the contents of the BR system variables ERR and LINE to determine the problem. If you type “GO”, the next line will be execute “system”, ending your program.&lt;br /&gt;
&lt;br /&gt;
If the file was in the middle of an upgrade when the error happened, it will be automatically rolled back to the previous version, so that when you fix the problem and try to run your program again, the file will again attempt to update from the beginning, and you won’t have to worry about corrupted data.&lt;br /&gt;
&lt;br /&gt;
However, please backup your data before upgrading your data files anyway, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Implementation of Keys / Creation of New Data Files:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The library has been expanded to automatically create all new data files, and to automatically update any existing files. This means that in the file layout header, two new fields that were previously ignored are no longer ignored. The RECL value that you specify in your file layout will be used, along with the description/definition of your keys file. When you open a new file (or update an existing one), the library will calculate the proper kps and kln by evaluating the key description. This key description must match up with subscript values from the data elements in your file, and more then one may be specified, but they must be separated with slashes (/). If I wanted my Farm File to be keyed based on CODE and NAME, the proper key description would be:&lt;br /&gt;
&lt;br /&gt;
  farm.key, CODE/NAME&lt;br /&gt;
&lt;br /&gt;
The library will then look up the position and length on disk of the CODE and NAME fields and put them together to create the proper keys during an update or creation of a new file. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;DataCrawler:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
Perhaps the most exciting new addition to the library is the addition of a programming tool I like to call a DataCrawler. If you run the FileIO Library directly as a program, instead of using it as a library, it will function as a DataCrawler. The DataCrawler requires a New Gui version of BR, as it requires a ListView to be able to properly and easily display the data in your files.&lt;br /&gt;
&lt;br /&gt;
If you run it in an older version of BR you will get a message, telling you to run it in a newer copy. If you run it in a New Gui version of BR with CONFIG GUI OFF, then GUI will be turned temporarily on for the use of the DataCrawler and then turned off again when you are finished. If you run it in a New Gui version of BR with GUI ON, it will just run normally.&lt;br /&gt;
&lt;br /&gt;
When you run the DataCrawler, first you will see a ListView displaying every file layout it can find in the filelay folder. If you select a file, the DataCrawler will open a large ListView with as many columns as there are fields in the file. The Column Headings will come from the element descriptions in your data files, and the column widths will come from the displayed width of the fields. There will be a row for every record in your data file, and you can resize the column widths, and scroll around the data file to view the raw data of your BR data files on disk.&lt;br /&gt;
&lt;br /&gt;
If you are dealing with a particularly enormous data file (50,000+ records) it can take a moment to populate the ListView with the data in your data file. You may hit ESC to stop loading if you like, and view only the already loaded records.&lt;br /&gt;
&lt;br /&gt;
If you would like to look up a particular record (based only upon the primary key for the data file), you may press F4. This will give you a window which asks you to input the key or partial key. When you press enter, the file will be reloaded, starting at the key you specified and continuing on to the end of the file, or until you press ESC. The records you are looking for should appear at the top of the ListView.&lt;br /&gt;
&lt;br /&gt;
To reset the ListView and look at the contents of the entire file again, simply press F4, and enter a blank (“”) key.&lt;br /&gt;
&lt;br /&gt;
Finally, as with any ListView, you may resort your data by clicking on any of the column headings. Then you can use the slider bar at the right to scroll down to the record you desire.&lt;br /&gt;
&lt;br /&gt;
This is a programming tool and is not designed to be used by an end user. This tool will open your file in read-only mode. It will not allow you to modify the data; I leave that as an exercise for the reader. However, it will update any datafiles you view to the latest version (if they need to be updated) when it opens them, just as any other program that uses the library will do.&lt;br /&gt;
&lt;br /&gt;
== Appendix (Examples)==&lt;br /&gt;
&lt;br /&gt;
=== Example.br ===&lt;br /&gt;
  00010    ! example.br - This program is an example of for the data reading simplification&lt;br /&gt;
  00020    ! Copyright April 2006 by Gabriel Bakker&lt;br /&gt;
  00030    ! Distributed open source as a Christmas gift to brag members&lt;br /&gt;
  00040    !&lt;br /&gt;
  00100    execute &amp;quot;config gui off&amp;quot;&lt;br /&gt;
  01020    DIM form$(1)*255&lt;br /&gt;
  01030    DIM color$(1)*255,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*255,colorcat(1)&lt;br /&gt;
  02020    library &amp;quot;fileio&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
  04000 !&lt;br /&gt;
  04010 Openfiles: ! Open your files here&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
  06000    ! gosub WriteFiles ! If you want to test this line, make sure to drop flag from 4030&lt;br /&gt;
  07000 !&lt;br /&gt;
  07010 MainBit: ! This&#039;un here&#039;s tha Main Bit&lt;br /&gt;
  07030    RESTORE #ColorFile:&lt;br /&gt;
  07100    ReadNextcolor: ! Read next record&lt;br /&gt;
  07120       read #ColorFile, using form$(ColorFile) : mat Color$, mat Color eof EndReadColor&lt;br /&gt;
  07180       PRINT Color$(co_name)&amp;amp;&amp;quot; (&amp;quot;&amp;amp;Color$(co_html)&amp;amp;&amp;quot;) is a member of the &#039;&amp;quot;;&lt;br /&gt;
  07190       PRINT trim$(fnReadDescription$(ColorcatFile,cc_Name,Color$(co_category),mat Colorcat$,mat Colorcat,mat form$))&amp;amp;&amp;quot;&#039; category.&amp;quot;&lt;br /&gt;
  07290       goto ReadNextColor&lt;br /&gt;
  07300    EndReadcolor: ! Finished with Color File&lt;br /&gt;
  08000    STOP&lt;br /&gt;
  25000 !&lt;br /&gt;
  25010 WriteFiles: ! Uncalled routine to demonstrate writing files&lt;br /&gt;
  25105       let color$(co_code)=&amp;quot;GD&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Gold&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;FFD700&amp;quot;&lt;br /&gt;
  25110       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25115       let color$(co_code)=&amp;quot;LV&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Lavender&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;BL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;E6E6FA&amp;quot;&lt;br /&gt;
  25120       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25125       let color$(co_Code)=&amp;quot;OR&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Orange&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;FFA500&amp;quot;&lt;br /&gt;
  25130       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25205       let colorcat$(cc_Code)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_Name)=&amp;quot;Yellows&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_html)=&amp;quot;FFFF00&amp;quot;&lt;br /&gt;
  25210       write #colorcatfile, using form$(colorcatfile): mat colorcat$,mat colorcat&lt;br /&gt;
  25215       let colorcat$(cc_Code)=&amp;quot;BL&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_Name)=&amp;quot;Blues&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_html)=&amp;quot;0000FF&amp;quot;&lt;br /&gt;
  25220       write #colorcatfile, using form$(colorcatfile): mat colorcat$,mat colorcat&lt;br /&gt;
  25300    return&lt;br /&gt;
  40000 !&lt;br /&gt;
  40010 Open: ! ***** Function to call library openfile and proc subs&lt;br /&gt;
  40020    def fnOpen(FILENAME$, MAT F$, MAT F, MAT FORM$;INPUTONLY,KEYNUM,___,INDEX)&lt;br /&gt;
  40025       dim _FileIOSubs$(1)*50&lt;br /&gt;
  40030       let fnopen=fnopenfile(FILENAME$, MAT F$, MAT F, MAT FORM$,INPUTONLY,KEYNUM,MAT _FileIOSubs$)&lt;br /&gt;
  40040       for Index=1 to udim(mat _FileIOSubs$) : execute (_FileIOSubs$(Index)) : next Index&lt;br /&gt;
  40090    fnend&lt;br /&gt;
  50000 !&lt;br /&gt;
  60000 Ignore: Continue&lt;br /&gt;
  &lt;br /&gt;
  Color File Layout&lt;br /&gt;
  color.dat, CO_, 1&lt;br /&gt;
  color.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Color Code,                  C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  CATEGORY$,      General Category of Color,   C    6&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
&lt;br /&gt;
  ColorCat File Layout&lt;br /&gt;
  colorcat.dat, CC_, 0&lt;br /&gt;
  colorcat.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Category Code,               C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
  &lt;br /&gt;
Example Layout showing multiple keys (price)&lt;br /&gt;
  price.dat, PR_, 0&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  X,              Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11016</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11016"/>
		<updated>2018-09-20T14:58:39Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Completed Future Change Requests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer.&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
&lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
&lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
Spring Conference 2017 Release, v2.3:&lt;br /&gt;
&lt;br /&gt;
*Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
*Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
*Added Version Number to Comments in Program&lt;br /&gt;
*Made fnDesignScreen callable as a function&lt;br /&gt;
*Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
*Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
*Added Screen Version field&lt;br /&gt;
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
*Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
*Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
*Began Tracking ScreenIO Version Carefully&lt;br /&gt;
&lt;br /&gt;
Previous Changes:&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11015</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=11015"/>
		<updated>2018-09-20T14:57:07Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Completed Future Change Requests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from its format on disk, into the date format you specify, and when its writing it back to the disk, it will convert it back to its format on disk, before writing it. This works in conjunction with the new [[#Support_for_New_Fileio_Dates|FileIO Date]] features, to allow you to specify the DATE format on disk for Date Fields.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
This also works in listviews to display the dates in any format you want, while still making sure they&#039;re numerically sortable.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== fnInit_ and fnFinal_ ======&lt;br /&gt;
&#039;&#039;Added in ScreenIO v91&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then [[#Listview_Prepopulate|Listview Pre/Post Populate]], and that exist along side your filter function, in the same file.&lt;br /&gt;
&lt;br /&gt;
fnInit_ is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_ is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Postpopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the fnInit_ and fnFinal_ functions are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters. fnFilterList$ becomes fnInit_FilterList and fnFinal_FilterList. fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
Because the Listview Pre and Post populate functions are almost exclusively used for things that have to do with the filter function, it is easier and more organized to keep the code together in one place.&lt;br /&gt;
&lt;br /&gt;
See [[#Listview_Filter_Function|Example]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedKeys$]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat SelectedRecords]]&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleKeys$]]&#039;&#039;&#039; - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;[[#Working_with_Listviews|mat VisibleRecords]]&#039;&#039;&#039; - All the records that are currently visible in the listview (v91,Requires BR 4.3+)&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Prewritten Functions =====&lt;br /&gt;
ScreenIO includes a few useful functions for working with listviews and other common operations, right out of the box. Most of them are pretty self explanatory, and include a comment right at the top of the function explaining what it does and how to use it. I&#039;ll mention a couple of them here.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;deletelistviewrecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the currently selected record in a listview.&lt;br /&gt;
*&#039;&#039;&#039;deleterecord&#039;&#039;&#039; - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.&lt;br /&gt;
*&#039;&#039;&#039;enforcerecord1&#039;&#039;&#039; - Use this as your enter event of an add/edit screen to force the screen to edit only record 1 of a data file, for example in a system configuration file that has only 1 record.&lt;br /&gt;
*&#039;&#039;&#039;enterselectionlistview, filterselection, and toggleselection&#039;&#039;&#039; - These three functions work together to make listview screens where the user can toggle on and off a selection of them.&lt;br /&gt;
*&#039;&#039;&#039;listviewcombo[...]&#039;&#039;&#039; - The functions that start with listviewcombo are used for making combination listview/add edit screens (Experimental feature) and are used automatically by the screen generator when you generate one.&lt;br /&gt;
*&#039;&#039;&#039;pause&#039;&#039;&#039; - assign this function to a button in your screen in order to pause your screen in the memory space of your custom helper library in order to debug things.&lt;br /&gt;
*&#039;&#039;&#039;printlistview&#039;&#039;&#039; - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer.&lt;br /&gt;
*&#039;&#039;&#039;exportlistviewcsv&#039;&#039;&#039; - This powerful function calls Laura Smiths fileio function to export everything in the current listview to a CSV and open it in the default editor (example excel).&lt;br /&gt;
*&#039;&#039;&#039;exportcurrentfilecsv&#039;&#039;&#039; - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there&#039;s a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. &#039;&#039;&#039;&#039;&#039;Note: &#039;&#039;&#039;If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====== ======&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     mat Employee$=(&amp;quot;&amp;quot;) : mat Employee=(0)&lt;br /&gt;
     &lt;br /&gt;
     read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore&lt;br /&gt;
     let s$(sio_EmployeeName)=Employee$(em_name)&lt;br /&gt;
  &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
  &lt;br /&gt;
  dim Employee$(1)*1023,Employee(1),Employee&lt;br /&gt;
  &lt;br /&gt;
  def fnInit_FilterTasks&lt;br /&gt;
     let Employee=fnOpen(&amp;quot;employee&amp;quot;,mat Employee$,mat Employee,mat Form$,1)&lt;br /&gt;
  fnend&lt;br /&gt;
  def fnFinal_FilterTasks&lt;br /&gt;
     Close #Employee:&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
fnInit_FilterTasks is run just prior to populating the listview, (after [[#Listview_Prepopulate|Listview Prepopulate]], and before the first record is read). fnFinal_FilterTasks is run just after populating the listveiw, (after the final row is read, and before [[#Listview_Prepopulate|Listview Postpopulate]]).&lt;br /&gt;
&lt;br /&gt;
The name of the [[#fnInit_and_fnFinal|fnInit_ and fnFinal_ functions]] are based on the name of the filter function, but they never have a $ or any parameters, and they&#039;re cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.&lt;br /&gt;
&lt;br /&gt;
When you create a new Filter Function in the newest versions of ScreenIO, they&#039;re automatically created for you, and you simply have to put whatever code you want to run in them. You can add them to your existing filter functions yourself, if you follow the same naming convention.&lt;br /&gt;
&lt;br /&gt;
These are the preferred method for populating listviews. They&#039;re better then [[#Listview_Prepopulate|Listview Prepopulate]] and [[#Listview_Prepopulate|Listview Postpopulate]]. However, [[#Listview_Prepopulate|Listview Pre/Post Populate]] will continue to work, for compatibility with existing programs.&lt;br /&gt;
&lt;br /&gt;
fnInit_ and fnFilter_ were added in ScreenIO v91.&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Working with Listviews =====&lt;br /&gt;
ScreenIO does a number of things to make writing custom functions to work with listviews easier. The currently selected record in the listview is always in mat F$ and mat F, and the primary key of that record is in CurrentKey$. You can use the standard BR system function rec(DataFile) to determine the current record of the data file.&lt;br /&gt;
&lt;br /&gt;
You can also use mat SelectedRecords and mat SelectedKeys$ to determine which row(s) are currently selected by the end user. This makes it a lot easier to work with multi-select listviews. And even if a listview does not allow multi-select, these arrays still work. They contain a single element and it points to the currently selected single row - the same thing you would find in CurrentKey$ and rec(Datafile). That makes it easy to create functions that work both for multi-select and non-multi-select listviews.&lt;br /&gt;
&lt;br /&gt;
BR 4.3 introduced Filter boxes. In BR 4.3 you can use mat VisibleRecords and mat VisibleKeys$, to see which records are currently displayed. They&#039;ll contain every row if the listview hasn&#039;t been filtered or sorted. But if the user has filtered or sorted the listview, by clicking on the column headings or typing something into a filter box, then these arrays will contain only the rows that are currently visible on the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Support for New Fileio Dates ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Supports the [[FileIO_Library#Support_for_Dates|FileIO Date features]] and if a field has a Date format specified, ScreenIO will automatically use that information to read and write the date correctly, even if its stored in a date other then Julian. This enables you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Filter Functions now include the ability to specify an &amp;quot;Init&amp;quot; and a &amp;quot;Final&amp;quot; function, all within the same filter function file. Init is called automatically, just prior to populating the listview, and Final is called just after. This is similar to the Listview Pre and Post Populate functions but its a lot easier to work with them all in the same .brs file with the filter function that they apply to. When you generate a new filter function it automatically makes shells of these functions for you. Just put whatever code you want in them (v2.5).&lt;br /&gt;
*ScreenIO now closes the screenio and screenfld data files right after reading them. This makes it possible to update your customers without kicking them out of the system. You no longer have to worry about a file sharing error on these files when installing updates (v2.49). &lt;br /&gt;
*Added support for FileIO&#039;s new date field types. If a field is a date field then ScreenIO automatically treats it like a date and sets it as a Date field. Additionally, ScreenIO now supports a new custom function parameter showing which fields from the file are Date fields (v2.48).&lt;br /&gt;
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) &lt;br /&gt;
*Fixed the Generate Screen function to use Filter Boxes (v2.47).&lt;br /&gt;
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).&lt;br /&gt;
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).&lt;br /&gt;
*Added feature where putting &amp;quot;N&amp;quot; in for the CNVRT spec property forces them to enter only valid numbers (v2.42).&lt;br /&gt;
*Added ability to put in just &amp;quot;N&amp;quot; instead of having to put the whole spec &amp;quot;N 10&amp;quot; for the CNVRT spec property (v2.42).&lt;br /&gt;
*Fixed a bug in the Orphaned Functions list (v2.4)&lt;br /&gt;
&lt;br /&gt;
*(Spring Conference 2017 Release, v2.3)&lt;br /&gt;
Added filter boxes for Screen Selection and Function Select&lt;br /&gt;
Added options to ini file to enable or disable them&lt;br /&gt;
  setting_Load_Filter&lt;br /&gt;
  setting_FunctionSel_Filter&lt;br /&gt;
Added Version Number to Comments in Program&lt;br /&gt;
Made fnDesignScreen callable as a function&lt;br /&gt;
Made File Layout List redraw every time so it reflects recent Layout Changes&lt;br /&gt;
Fixed a bug in the &amp;quot;Launch Screen in New Window&amp;quot; code&lt;br /&gt;
Added Screen Version field&lt;br /&gt;
Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts&lt;br /&gt;
Fixed a compatibility issue for using Substitute to rearrange your folder structure&lt;br /&gt;
Added a better message for Out Of Date Helper Libraries&lt;br /&gt;
Began Tracking ScreenIO Version Carefully&lt;br /&gt;
(Spring Conference 2017 Release)&lt;br /&gt;
&lt;br /&gt;
*mat VisibleKeys$, mat VisibleRecords which handle the keys and record numbers of all rows on the current listview that are Currently Visible (v91)&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10974</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10974"/>
		<updated>2018-09-18T16:57:26Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* mat VisibleRecords and Mat VisibleKeys$ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from a julian date into the date format you specify, and when its writing it back to the disk, it will convert it back to the julian date value before saving it to the disk.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - this is obvious, but if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedKeys$&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to CurrentKey$ above. Therefore you can use Mat SelectedKeys$ to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedRecords&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to rec(Datafile) above. Therefore you can use Mat SelectedRecords to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;Mat VisibleRecords and Mat VisibleKeys$&#039;&#039;&#039; to tell which rows are currently visible in the filtered listview (v91,Requires BR 4.3+)&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== Mat VisibleRecords and Mat VisibleKeys$ =====&lt;br /&gt;
ScreenIO (v91) now also provides your custom functions with two new arrays, mat VisibleRecords and mat VisibleKeys$. These arrays work on a listview screen, and they contain the keys and record numbers of all rows on the current listview that are Currently Visible. If the user uses a filter box to filter the listview, or sorts the columns in the list, these arrays update in real time, telling your functions exactly which records are currently visible in the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
Going along with that, there is a new function called ExportCurrentFileCSV, which exports any (user selectable) fields from the data file in a CSV format, for any records that are currently displayed on the list, taking into account the current filters and sorts. It works like the old ExportListviewCSV function except that it enables the end user to select which fields they want to export, and they can choose from any in the file.&lt;br /&gt;
&lt;br /&gt;
(If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.)&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Support for New Fileio Dates ==&lt;br /&gt;
&lt;br /&gt;
This update adds support for the new FileIO Dates to ScreenIO, and it also adds support for ScreenIO Date Processing to non-Julian date formats. This will enable you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Support for new FileIO Dates formatting (v91)&lt;br /&gt;
*mat VisibleKeys$, mat VisibleRecords which handle the keys and record numbers of all rows on the current listview that are Currently Visible (v91)&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10973</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10973"/>
		<updated>2018-09-18T16:57:03Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* ExitMode */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from a julian date into the date format you specify, and when its writing it back to the disk, it will convert it back to the julian date value before saving it to the disk.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - this is obvious, but if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedKeys$&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to CurrentKey$ above. Therefore you can use Mat SelectedKeys$ to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedRecords&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to rec(Datafile) above. Therefore you can use Mat SelectedRecords to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;Mat VisibleRecords and Mat VisibleKeys$&#039;&#039;&#039; to tell which rows are currently visible in the filtered listview (v91,Requires BR 4.3+)&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
===== mat VisibleRecords and Mat VisibleKeys$ =====&lt;br /&gt;
ScreenIO (v91) now also provides your custom functions with two new arrays, mat VisibleRecords and mat VisibleKeys$. These arrays work on a listview screen, and they contain the keys and record numbers of all rows on the current listview that are Currently Visible. If the user uses a filter box to filter the listview, or sorts the columns in the list, these arrays update in real time, telling your functions exactly which records are currently visible in the list, and in what order.&lt;br /&gt;
&lt;br /&gt;
Going along with that, there is a new function called ExportCurrentFileCSV, which exports any (user selectable) fields from the data file in a CSV format, for any records that are currently displayed on the list, taking into account the current filters and sorts. It works like the old ExportListviewCSV function except that it enables the end user to select which fields they want to export, and they can choose from any in the file.&lt;br /&gt;
&lt;br /&gt;
(If you want to only give them access to certain fields, make a copy of your layout and mark out whatever fields you want to hide by making them &amp;quot;X&amp;quot; fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.)&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Support for New Fileio Dates ==&lt;br /&gt;
&lt;br /&gt;
This update adds support for the new FileIO Dates to ScreenIO, and it also adds support for ScreenIO Date Processing to non-Julian date formats. This will enable you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Support for new FileIO Dates formatting (v91)&lt;br /&gt;
*mat VisibleKeys$, mat VisibleRecords which handle the keys and record numbers of all rows on the current listview that are Currently Visible (v91)&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10972</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10972"/>
		<updated>2018-09-18T16:49:02Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Custom Screen Function Parameters */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from a julian date into the date format you specify, and when its writing it back to the disk, it will convert it back to the julian date value before saving it to the disk.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - this is obvious, but if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedKeys$&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to CurrentKey$ above. Therefore you can use Mat SelectedKeys$ to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedRecords&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to rec(Datafile) above. Therefore you can use Mat SelectedRecords to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;Mat VisibleRecords and Mat VisibleKeys$&#039;&#039;&#039; to tell which rows are currently visible in the filtered listview (v91,Requires BR 4.3+)&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Support for New Fileio Dates ==&lt;br /&gt;
&lt;br /&gt;
This update adds support for the new FileIO Dates to ScreenIO, and it also adds support for ScreenIO Date Processing to non-Julian date formats. This will enable you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Support for new FileIO Dates formatting (v91)&lt;br /&gt;
*mat VisibleKeys$, mat VisibleRecords which handle the keys and record numbers of all rows on the current listview that are Currently Visible (v91)&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=File:Dates2.png&amp;diff=10971</id>
		<title>File:Dates2.png</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=File:Dates2.png&amp;diff=10971"/>
		<updated>2018-09-18T16:25:12Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=File:Dates1.png&amp;diff=10970</id>
		<title>File:Dates1.png</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=File:Dates1.png&amp;diff=10970"/>
		<updated>2018-09-18T16:24:32Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10969</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10969"/>
		<updated>2018-09-18T16:23:55Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Making ScreenIO Screens */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from a julian date into the date format you specify, and when its writing it back to the disk, it will convert it back to the julian date value before saving it to the disk.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - this is obvious, but if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedKeys$&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to CurrentKey$ above. Therefore you can use Mat SelectedKeys$ to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedRecords&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to rec(Datafile) above. Therefore you can use Mat SelectedRecords to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Support for New Fileio Dates ==&lt;br /&gt;
&lt;br /&gt;
This update adds support for the new FileIO Dates to ScreenIO, and it also adds support for ScreenIO Date Processing to non-Julian date formats. This will enable you to use ScreenIO Date fields for your legacy data files that stored their dates in another format.&lt;br /&gt;
&lt;br /&gt;
There is now a new Control Attribute called &amp;quot;Disk Date Format&amp;quot; that, if specified, tells ScreenIO to unpack the field to Julian before processing it. It works along with the DATE Conversion Spec Control Attribute, (which previously only worked with dates stored as Julian), to enable a lot of useful date editing features.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates1.png]]&lt;br /&gt;
&lt;br /&gt;
This works on listviews too, so you can now specify these two fields, to make dates show as, for example &amp;quot;January 24, 2018&amp;quot;, even if they&#039;re saved on disk as &amp;quot;MMDDCCYY&amp;quot;. Or, like in the following example, as &amp;quot;MM/DD/CCYY&amp;quot; even though they&#039;re saved on disk as &amp;quot;MDY&amp;quot;. Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates2.png]]&lt;br /&gt;
&lt;br /&gt;
Note: If you specify the Date format in your file layout, following the instructions for FileIO above, then ScreenIO detects that and fills in these fields for you, automatically enabling Date processing.&lt;br /&gt;
&lt;br /&gt;
ScreenIO also has a new INI setting you can control:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 setting_DateFormatDisplay$=&amp;quot;m/d/cy&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This determines the default date format to use when you add fields that are marked in FileIO as Date Fields. This is the format you want your end users to see and interact with.&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Support for new FileIO Dates formatting (v91)&lt;br /&gt;
*mat VisibleKeys$, mat VisibleRecords which handle the keys and record numbers of all rows on the current listview that are Currently Visible (v91)&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10968</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10968"/>
		<updated>2018-09-18T16:16:38Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Completed Future Change Requests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from a julian date into the date format you specify, and when its writing it back to the disk, it will convert it back to the julian date value before saving it to the disk.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - this is obvious, but if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedKeys$&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to CurrentKey$ above. Therefore you can use Mat SelectedKeys$ to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedRecords&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to rec(Datafile) above. Therefore you can use Mat SelectedRecords to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Support for new FileIO Dates formatting (v91)&lt;br /&gt;
*mat VisibleKeys$, mat VisibleRecords which handle the keys and record numbers of all rows on the current listview that are Currently Visible (v91)&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=FileIO_Library&amp;diff=10967</id>
		<title>FileIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=FileIO_Library&amp;diff=10967"/>
		<updated>2018-09-18T16:11:44Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Support for Dates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;FileIO&#039;&#039;&#039; Library began as a project to find a way to reduce the headache associated with making changes to data files. In my experiences working for [[BRC]], I had to make a change to the commun file, a data file that stores information about communication with EDI VANs. I added some new fields, and removed a couple of old fields, and then I began searching through the BRC program suite to find and modify each program that referenced this data file in order to update it with the proper new form statement. This task quickly became daunting as I noticed that out of BRC’s program suite of over 600 programs, more than one third of them referenced the commun file. With 223 programs to modify, the task was given up as hopeless and tabled indefinitely.&lt;br /&gt;
&lt;br /&gt;
I am happy to announce that we have solved this problem. When I have to make a change to a data file layout for my customers today, I can complete the task in under 1 minute, and not a single program needs to be changed in order to continue working with the new file layout. In fact, I don’t even have to update my customer’s data files, as the FileIO library takes care of this for me as well.&lt;br /&gt;
&lt;br /&gt;
The trick is to define your file layouts in an ASCII text file layout file that I will tell you about in a minute. The FileIO Library will actually parse through your file layouts, and it will instruct your programs how to read the data file, so that you don’t have to. It will also automatically detect when you make changes to the file layout, and it will update your customer’s data files on the fly to make sure they have the latest version. Finally, it even contains a DataCrawler that you can use to examine the contents of any of your BR data files in a raw format.&lt;br /&gt;
&lt;br /&gt;
For more information about the FileIO Library visit the [http://www.sageax.com/products/fileio-library/ Sage AX Website]&lt;br /&gt;
&lt;br /&gt;
To download the latest copy of FileIO, click [http://www.sageax.com/downloads/FileIO.zip here.]&lt;br /&gt;
&lt;br /&gt;
== Method of Operation ==&lt;br /&gt;
The file IO library parses a formatted text file layout and uses this information to structure the opening and initializing of the reading of a file “object”. The word object here is used to refer to all the data in a given record layout in one of your files. This library is easy to use, and provided you follow some simple standards, it will simplify your life immensely.&lt;br /&gt;
&lt;br /&gt;
You will need to define one array for all forms and add a snippet of code (given below) to the program for interfacing with with the library. For each file you will need to define a couple of arrays and use the library to open them. From that point on access to data is simple and direct. &lt;br /&gt;
&lt;br /&gt;
=== File Object Arrays ===&lt;br /&gt;
&lt;br /&gt;
First, in your program you must create two arrays to store the file information. If we are dealing with the Color File these would be MAT COLOR$ and MAT COLOR. One will store all the string information about a color, and the other will store all the numeric data. Our working example will involve two files: a Color File and a Color Category File. You should dimension these to:&lt;br /&gt;
&lt;br /&gt;
  01030    DIM color$(1)*1000,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*1000,colorcat(1)&lt;br /&gt;
&lt;br /&gt;
We&#039;re dimensioning the string arrays to 1000. This is the length of one field in the color file. It needs to be at least as big as the largest string field in the data file.&lt;br /&gt;
&lt;br /&gt;
However, it is recommended to make sure the length is long enough to handle any field you might eventually add to the file at any point in the future. BR supports multi-line textboxes, so I sometimes add long memo fields to my data files that might be 400 or 800 or even 1000 characters long, therefore 1000 is the length I use now in all my new development.&lt;br /&gt;
&lt;br /&gt;
But anything will work as long as its long enough to handle the largest data field in your file.&lt;br /&gt;
&lt;br /&gt;
=== Forms Array ===&lt;br /&gt;
&lt;br /&gt;
You will also need a variable to store the form statement associated with reading the files. This form statement will be dynamically generated whenever a new file is opened. It will say: &lt;br /&gt;
&lt;br /&gt;
  01020    DIM form$(1)*255&lt;br /&gt;
&lt;br /&gt;
This form statement will be compiled by the FileIO open statement and BR limits all form statements to 255 bytes compiled anyway, so 255 is enough for the Forms$ array.&lt;br /&gt;
&lt;br /&gt;
=== Library Linkage ===&lt;br /&gt;
&lt;br /&gt;
You will also need the library statement:&lt;br /&gt;
&lt;br /&gt;
  02020 library &amp;quot;fileio.br&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
&lt;br /&gt;
=== fnOpen Function ===&lt;br /&gt;
&lt;br /&gt;
Now, add a snippet of code to interface with the library.&lt;br /&gt;
&lt;br /&gt;
Because BR libraries do not share variables with the programs they are called from, we will need to execute a proc file whenever we open a file to set the names of all our variables after we return. Add the following snippet of code into your program. It will create an FnOpen function that calls the library version and runs the proc file. The $$$ at the end of the procfile name tells the procfile to self-destruct after execution. Since this procfile is used simply to return variable information back from the library to the main program, we don’t need it sitting around collecting dust.&lt;br /&gt;
&lt;br /&gt;
  99010 OPEN: ! ***** Function To Call Library Openfile And Proc Subs&lt;br /&gt;
  99020    def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths,Supress_Prompt,Ignore_Errors,Suppress_Log,___,Index)&lt;br /&gt;
  99030       dim _FileIOSubs$(1)*800, _Loadedsubs$(1)*80&lt;br /&gt;
  99040       let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$, Supress_Prompt,Ignore_Errors,Program$,Suppress_Log)&lt;br /&gt;
  99050       if Srch(_Loadedsubs$,Uprc$(Filename$))&amp;lt;=0 then : mat _Loadedsubs$(Udim(_Loadedsubs$)+1) : let _Loadedsubs$(Udim(_Loadedsubs$))=Uprc$(Filename$) : for Index=1 to Udim(Mat _Fileiosubs$) : execute (_Fileiosubs$(Index)) : next Index&lt;br /&gt;
  99060    fnend&lt;br /&gt;
&lt;br /&gt;
Or, for those with [[Lexi]]:&lt;br /&gt;
  OPEN: ! ***** Function To Call Library Openfile And Proc Subs&lt;br /&gt;
     def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths,Supress_Prompt,Ignore_Errors,Suppress_Log,___,Index)&lt;br /&gt;
        dim _FileIOSubs$(1)*800, _Loadedsubs$(1)*80&lt;br /&gt;
        let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$, Supress_Prompt,Ignore_Errors,Program$,Suppress_Log)&lt;br /&gt;
        if Srch(_Loadedsubs$,Uprc$(Filename$))&amp;lt;=0 then : mat _Loadedsubs$(Udim(_Loadedsubs$)+1) : let _Loadedsubs$(Udim(_Loadedsubs$))=Uprc$(Filename$) : for Index=1 to Udim(Mat _Fileiosubs$) : execute (_Fileiosubs$(Index)) : next Index&lt;br /&gt;
     fnend&lt;br /&gt;
&lt;br /&gt;
=== Using FileIO in Your Programs ===&lt;br /&gt;
Now you are ready to process files. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;You simply open the files by saying:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;read each file as follows:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  30120    read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore  &lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;and access the data:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  30180    LET ColorCode$=color$(co_Code) !:&lt;br /&gt;
           LET ColorName$=color$(co_Name)&lt;br /&gt;
&lt;br /&gt;
=== How it Works ===&lt;br /&gt;
These statements tell the File Library to look in the filelay folder to find the file layout for the Color File, and read it to find out what the Color File looks like. Then Open the Color File, and set MAT COLOR$ and MAT COLOR to the correct number of elements to hold an entire color record. Finally, it will define several variables that we can use as pointers into (subscripts) these arrays to access the data we after reading it, and it will place the file handle into a variable called colorfile.&lt;br /&gt;
&lt;br /&gt;
The second open above will do the same thing to the color category file, except the 1 parameter tells the function to open readonly. The subscripts array will be executed, creating the subscripts in memory, and the pointers (subscripts) will be set in the calling program. So, if I had a file layout such as the following:&lt;br /&gt;
&lt;br /&gt;
  color.dat, CO_, 1&lt;br /&gt;
  color.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Color Code,                  C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  CATEGORY$,      General Category of Color,   C    6&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
&lt;br /&gt;
Then the functions would do the same thing as the following individual lines of code (assuming the next available file handle was 5):&lt;br /&gt;
&lt;br /&gt;
  DIM FORM$(5)*255&lt;br /&gt;
  DIM COLOR$(9)*1023, COLOR(1)&lt;br /&gt;
  OPEN #5: “Name=color.dat, kfname=color.key”,internal,outin,keyed&lt;br /&gt;
  LET FORM$(5)=”form C 6,V 30,V 6,C 6”&lt;br /&gt;
  LET FORM$(5)=CFORM$(FORM$(5))&lt;br /&gt;
  LET COLORFILE=5&lt;br /&gt;
  CO_CODE=1&lt;br /&gt;
  CO_NAME=2&lt;br /&gt;
  CO_CATEGORY=3&lt;br /&gt;
  CO_HTML=4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The data is used by referencing the file array, with the subscript name, so the color’s description becomes color$(co_Name).&lt;br /&gt;
&lt;br /&gt;
In the old days, if we wanted to change the file layout of our file, all of the programs that used that file would have to be changed one at a time to use the new file layout. Also, if the order of the fields changed, then all the programs would have to also be changed to use the new fields.&lt;br /&gt;
&lt;br /&gt;
But now, using this function, we can change the file layout all we want. If we later want to insert a field into the file layout before color name, I won’t have to look at this program again; this program will just work fine, because the library maps the subscripts to the actual fields.&lt;br /&gt;
&lt;br /&gt;
Also, the code is easier to read and maintain.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
The whole thing looks like this:&lt;br /&gt;
&lt;br /&gt;
  01025    ! Dimension the Arrays&lt;br /&gt;
  01030    DIM color$(1)*1023,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*1023,colorcat(1)&lt;br /&gt;
  01050    DIM form$(1)*255&lt;br /&gt;
  02000 !&lt;br /&gt;
  02020 library &amp;quot;fileio.br&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$) ! Open the file&lt;br /&gt;
  05000 ! &lt;br /&gt;
  30120    read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore ! Read the file&lt;br /&gt;
  30180    LET ColorCode$=color$(co_Code) !:&lt;br /&gt;
           LET ColorName$=color$(co_Name) ! Use the data by referincing it in the file arrays&lt;br /&gt;
  80000 !&lt;br /&gt;
  90000 ! Every program using fileio needs the following code&lt;br /&gt;
  99010  OPEN: ! ***** Function To Call Library Openfile And Generate Subs&lt;br /&gt;
  99020     def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths)&lt;br /&gt;
  99030        dim _FileIOSubs$(1)*800&lt;br /&gt;
  99040        let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$)&lt;br /&gt;
  99050        for Index=1 to udim(mat _FileIOSubs$) : execute (_FileIOSubs$(Index)) : next Index&lt;br /&gt;
  99060     fnend&lt;br /&gt;
&lt;br /&gt;
== File Layouts ==&lt;br /&gt;
Now lets inspect the anatomy of a properly formatted file layout. These should be placed in a subdirectory called filelay.&lt;br /&gt;
&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  X,              Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
&lt;br /&gt;
The first line contains the name of the Farm File, a unique string to prefix all of your subscript pointers, and the file version number. The subscript value is to ensure that the program knows the difference between the Farm File’s Farm Code, and the Route File’s Route Code. (One will be RT_CODE and the other is FM_CODE).  These are separated by a comma. Spacing does not matter, so adjust your spacing so that it looks nice.&lt;br /&gt;
&lt;br /&gt;
The Version number is used to determine when the data has changed, and an update needs to be made to your data file. Your file layouts should all start at version 0, and each time you want to make a change, you may increment this value by 1.&lt;br /&gt;
&lt;br /&gt;
Each time you open a file with the FILEIO library, it reads the file version number of the file on disk (using the BR version() function), and then it compares it to the version number in your file layout. If your file layout has a higher version number then your existing data file, then the library opens the backup of the file layout for the version of the data file that exists on disk. It makes a backup copy of the existing data file, and creates a new file with the proper version number. Then it reads your records one at a time, and copies all the data from the old file into the new file one field at a time. If a field is dropped from the file layout, that data gets lost. If fields are rearranged, the data is copied and saved in the new file in the new positions. If a new field is added, it starts out blank (or 0).&lt;br /&gt;
&lt;br /&gt;
If you look in the filelay folder, you will notice a version folder. This contains several files ending with a number. For example you may see a color.0, and a color.1 file.&lt;br /&gt;
&lt;br /&gt;
If you run the fnopen function and it can not find your data file (usually because this is a new file and it hasn’t been created yet), &#039;&#039;the library will automatically create your file,&#039;&#039; based on the information you give in the first part of the file layout.&lt;br /&gt;
&lt;br /&gt;
Also, whenever you make changes to your file layout, the function library will automatically update the data files on disk for you. It does this by renaming the old file, creating a new one with the new version number, and then copying the data from the old one to the new one a record at a time.&lt;br /&gt;
&lt;br /&gt;
Any time it creates a file, or updates the file on disk, it creates a backup of the file &#039;&#039;layout&#039;&#039;. The first time you run a program that tries to read your new data file, it will create the data file for you and make a backup of the layout, and if the number in your file layout is 0, then it will create, for example, a filelay\version\price.0 file, a backup of your file layout that the library uses to figure out what has changed the next time you try to update the file.&lt;br /&gt;
&lt;br /&gt;
If you wish to make any changes to this data file, first you increment the version number, (in this case make the 0 into a 1). Then change the file layout all you want. You may rearrange fields, add new fields, add or remove keys, or change the record length.&lt;br /&gt;
&lt;br /&gt;
The only step necessary for having your data files updated is to increment the version number every time you make a change to the file layout.&lt;br /&gt;
&lt;br /&gt;
You may make any changes you like to the file layouts, but do not change the names of your existing subscripts. If you change the subscript name, not only will all the programs that reference that subscript be broken, but additionally, the routine will not understand that you are changing the name. It will think you are dropping the old field and adding a new field and any data stored in this location will be lost when the file is updated.&lt;br /&gt;
&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
&lt;br /&gt;
The second line contains the name of the first key, and a definition telling what the key is based on. These are separated by a comma. The key definition is made up of each of the subscript names in this file that form the keyfields for the file. When the library is called to open a file, if the file does not exist, or if it needs to be updated, a new one will be created. The function will read these subscript names that form your key definitions, and it will calculate the proper key position (KPS=) and length (KLN=) values. Then the create routine will use this information with the Index command to create the new key files.&lt;br /&gt;
&lt;br /&gt;
  price.key, ITEM&lt;br /&gt;
  price.ky2, FARM&lt;br /&gt;
  price.ky3, ITEM/FARM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
&lt;br /&gt;
Notice that the third key is based on three different fields. These are separated by a “/”. It is important that you use a “/” to separate your keys when you are building a key out of more then one field, because the function uses this “/” to help it make the proper BR syntax for defining complex key fields.&lt;br /&gt;
&lt;br /&gt;
The file can have as many keys as you want. The function will keep parsing key file names until it reaches the next part of the layout. It opens any OutIn files with all keys so that any changes you may make to the data stored on disk will be properly reflected in all the key files.&lt;br /&gt;
&lt;br /&gt;
The optional RECL= Parameter is read and used whenever a new file is created or an old one is updated. If it is not specified, the record length is calculated from the fields in the layout.&lt;br /&gt;
&lt;br /&gt;
  ===================================================&lt;br /&gt;
&lt;br /&gt;
The next line in the file is skipped by the parsing routine, and its purpose is to make the file layouts more readable to a programmer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
&lt;br /&gt;
Following the file and key structure, the fields are defined. There are three parameters on each field definition line, and you make one line for each field in your file layout. The first parameter is the subscript name that you will use in your program to refer to this data element. Place a $ at the end of the subscript name for all string elements. Don’t place anything at the end of the subscript name for numeric elements. Note that each of these names will be prefixed by the second parameter of the very first line of this layout. &lt;br /&gt;
&lt;br /&gt;
The second parameter is the description. This description is for the benefit of the programmer, so when the programmer is reading the file layouts, (s)he can tell which field does what. The spaces are ignored, so you may include as many spaces as you wish to make the layout look good. It does seem like good general guidelines would be to limit your layout lines to 255 characters and your descriptions to 80. &lt;br /&gt;
&lt;br /&gt;
The description is also used by the built in DataCrawler, a program that reads any of your data files and displays the entire contents in raw form in a listview. The Descriptions become the headings for each column in the listview. &lt;br /&gt;
&lt;br /&gt;
Those descriptions are also used for the default captions for your fields if you use ScreenIO, a library for building GUI programs that itself builds off of fileio.&lt;br /&gt;
&lt;br /&gt;
The third parameter is the form statement, which is pretty straightforward. Any items with a form statement of type “X” will be ignored, except that the length will still be used to calculate the position on disk of all remaining fields in the record. The library will take X fields into consideration when building the form statement, but not at any other time.&lt;br /&gt;
&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
Comment line text must begin with an exclamation point, but it may be indented. Comment lines may appear anywhere (vertically) and are ignored. &amp;lt;br&amp;gt;&lt;br /&gt;
Blank lines are ignored as well.&lt;br /&gt;
&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
After the last field definition, an &#039;&#039;optional&#039;&#039; #eof# line may be specified, in which case any lines after that will be ignored. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  DUMMY,          Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
&lt;br /&gt;
And that’s all there is to it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tips ===&lt;br /&gt;
&lt;br /&gt;
When you&#039;re making new layouts, a missing comma can cause FileIO to parse the layout wrong and give you errors. Here are a couple tips to help ensure your layouts are error free before using them in your programs.&lt;br /&gt;
&lt;br /&gt;
*Use the Data Crawler to test your layout. The data crawler is the simplest way to test your new layout without writing any code. It opens it and accesses the file in a very simple and straight forward manor to help identify any errors in the layout that you might have.&lt;br /&gt;
&lt;br /&gt;
*If you have trouble with the form statement, you can&#039;t see whats in it because FileIO uses CForm$ to compile your form statement to make your programs run faster. But here&#039;s a way to tell what the original form statement was that FileIO generated when it put the strings first and numbers last in your program: Open the file in the Data Crawler. When you get an error, type &amp;quot;Print FormStatement$&amp;quot; to see the original form statement.&lt;br /&gt;
&lt;br /&gt;
This works even if your file is working fine. Any time the file is opened with the data crawler, you can press CTRL-A and then type PRINT FormStatement$ and it will print out the uncompiled form statement for the file.&lt;br /&gt;
&lt;br /&gt;
== Support for Dates ==&lt;br /&gt;
As of V2.48, file layouts support dates in any storage formats on disk. Whether you store your dates in Julian or in YMD or MDY or any other format, specify so in the 4th column of your file layouts, using the FileIO Date Keyword. ex: DATE(Julian) or DATE(YMD) or any other valid BR Date Format.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates0.png]]&lt;br /&gt;
&lt;br /&gt;
When this is specified, it enables the FileIO data exploration tool (Data Crawler) to display the dates in human readable format. This works for both Viewing, and for Editing.&lt;br /&gt;
&lt;br /&gt;
The new Date functionality also supports the File Layout Upgrade facility, allowing you to change the format of your dates on disk and FileIO will handle it automatically, upgrading the field to use the new date format for you.&lt;br /&gt;
&lt;br /&gt;
It works also for Exporting your data files to CSV, and is supported automatically in the FileIO functions that do those exports. It converts the dates on export to a standard format (Default: m/d/cy) that you can specify in your FileIO.Ini File.&lt;br /&gt;
&lt;br /&gt;
This update adds two new ini file options:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
 DateFormatExport$=&#039;m/d/cy&#039;  ! Format of Dates when Exporting to CSV&lt;br /&gt;
 DateFormatDisplay$=&#039;m/d/cy&#039; ! Format of Dates when displaying in Data Crawler&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can use these to specify your preferred Date format for Viewing/Editing, and your preferred Date format for Exporting.&lt;br /&gt;
&lt;br /&gt;
Remember, you can see the full list of FileIO ini file options, by looking in the source code at the top of FileIO.&lt;br /&gt;
&lt;br /&gt;
There is a new optional parameter for all layout reading functions, mat NDateSpec$ and mat SDateSpec$ which correspond with the other arrays, to let you know which fields are date fields, so that you can develop routines in your programs to automatically pack and unpack the dates.&lt;br /&gt;
&lt;br /&gt;
Important Note: Using FileIO, the reading of the data file is still done directly in your programs. So this does not change how your existing programs work. It does not unpack the dates for you in your programs. You still have to do all that.&lt;br /&gt;
&lt;br /&gt;
For this reason, upgrading to the new Date processing will not break any of your current code.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
Now that you have your file layouts defined, you have access to several powerful utilities right out of the box using Fileio. Additionally, several more utilities are available as [[#FileIO_Add-on_Packages|Add-Ons]], including our most popular development tool [[Screenio|ScreenIO]]. You can read more about them in their section below.&lt;br /&gt;
&lt;br /&gt;
But for now, lets take a look at some of the wonderful free utilities that come built into Fileio.&lt;br /&gt;
&lt;br /&gt;
Some of these utilities are accessible from your code via library functions, but the primary way you access any of them is by simply loading the FileIO Library and running it directly.&lt;br /&gt;
&lt;br /&gt;
=== DataCrawler ===&lt;br /&gt;
The data crawler is the original utility of FileIO. This utility shows you first a list of all data files allowing you to select one.&lt;br /&gt;
&lt;br /&gt;
Select a data file and press enter, and FileIO will then display a listview containing all the data in the data file. This list is sized based on the size of your main BR window (window 0) automatically to take up the full size available to it, so if you want to see more, try [[Open Window|opening window 0]] larger before running FileIO.&lt;br /&gt;
&lt;br /&gt;
At the top of the window is a filter box, and you can type anything you want in there and click &amp;quot;Refresh&amp;quot; and it will reread the data file, shortening the list to show only those records that match (case insensitive) what you have typed.&lt;br /&gt;
&lt;br /&gt;
If you have ScreenIO installed, then FileIO&#039;s data crawler will take advantage of the included Animation Engine in ScreenIO to animate a loading window while the listview is displaying. If you don&#039;t have ScreenIO then FileIO will simply load the listview.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want to wait for the entire file to load, press ESC to stop the load process.&lt;br /&gt;
&lt;br /&gt;
If the file is empty, FileIO will display a message box letting you know.&lt;br /&gt;
&lt;br /&gt;
This tool is very useful for sorting out data errors. It will allow you to look inside any data file you have a layout for and directly view the data there.&lt;br /&gt;
&lt;br /&gt;
At the bottom of the Data Crawler are several buttons. There&#039;s a Jump button that repositions the file by a key you specify and then loads the list with the data from that key on down to the end of the file.&lt;br /&gt;
&lt;br /&gt;
There is a &amp;quot;Columns&amp;quot; button which you can use to decide which columns should show up on the listview. Fewer columns means faster loading so sometimes for large files I press ESC immediately when the file first starts loading to cancel the load. Then I click &amp;quot;Columns&amp;quot; and check only the columns I want to see. Finally I press the &amp;quot;Refresh&amp;quot; button to trigger it to read the file again and this time it loads much faster then before.&lt;br /&gt;
&lt;br /&gt;
Next you&#039;ll find an Export button which starts the process for exporting a file to CSV. You can read more on that in the next section. And next to that is a Quit button.&lt;br /&gt;
&lt;br /&gt;
In this example, we loaded the file &amp;quot;Read Only&amp;quot; so it put everything in a listview. But there are times when its useful to fix data errors this way too, especially during development. So if you want to directly edit your data file, on the first page select the file you want to edit and instead of pressing &amp;quot;Enter&amp;quot; or clicking &amp;quot;View&amp;quot;, this time press &amp;quot;F5&amp;quot;. F5 is the secret Edit button that loads a data file into a grid instead.&lt;br /&gt;
&lt;br /&gt;
You can use the grid to change records, delete them or add them, and in addition to the buttons listed above, it also has an &amp;quot;Import&amp;quot; button for importing a CSV file into this data file.&lt;br /&gt;
&lt;br /&gt;
Any changes you make to the data file are not saved until you click the &amp;quot;Save&amp;quot; button (which also only appears when you&#039;re in Edit mode).&lt;br /&gt;
&lt;br /&gt;
In the 01/2015 release of FileIO, each records rec # is displayed in the listview, to aid in debugging bad data problems.&lt;br /&gt;
&lt;br /&gt;
==== Debugging Tip ====&lt;br /&gt;
Any time you&#039;re viewing a file layout in the Data Crawler, you can see the Uncompiled Form Statement by pressing CTRL-A to get to an ATTN prompt, and then entering the command:&lt;br /&gt;
&lt;br /&gt;
  print FormStatement$&lt;br /&gt;
&lt;br /&gt;
and it will print out the original form statement.&lt;br /&gt;
&lt;br /&gt;
==== Another Debugging Tip ====&lt;br /&gt;
&lt;br /&gt;
The FileIO Datacrawler ignores records that it cannot read. This is to allow for data files that have multiple record layouts in one data file. You make a custom layout for each record type and the data crawler shows just the records that match that type in the file.&lt;br /&gt;
&lt;br /&gt;
However that becomes a problem when you&#039;re making a layout to work with an existing data file. Error 726 indicates that something minor in the file layout doesn&#039;t match the data on the disk, but these errors are ignored so you might see either an empty data file, or a data file with some records missing. If that happens, you need to see the missing records in order to figure out what is wrong with your layout. &#039;&#039;&#039;&#039;&#039;It&#039;s very important that you don&#039;t try to use a file layout that isn&#039;t quite working right. Make sure your layout works and can read every record of a file that it should read before using it.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To see the records that could not be read in a file, run the data crawler on the layout, then press CTRL-A to get an ATTN prompt. From there, enter the command&lt;br /&gt;
&lt;br /&gt;
  print mat BadRead$&lt;br /&gt;
&lt;br /&gt;
and it will print all the records that were ignored because the file layout didn&#039;t match them. It prints out the raw data from the file.&lt;br /&gt;
&lt;br /&gt;
==== Function Access to use Data Crawler in your programs ====&lt;br /&gt;
You can use the data crawler in your own programs by using one of the following functions:&lt;br /&gt;
* [[#fnDataCrawler|fnDataCrawler]] - Open a Listview showing the data file&lt;br /&gt;
* [[#fnDataEdit|fnDataEdit]] - Display the data in an editable grid&lt;br /&gt;
* [[#fnShowData|fnShowData]] - This function does the same thing as the above two, but with many many more options allowing you to customize exactly what appears and exactly what they&#039;re allowed to change.&lt;br /&gt;
&lt;br /&gt;
Note: its not recommended to allow your customers to use the data crawler to access your data files directly. There&#039;s no way to specify validations or do anything complicated, so unless you&#039;re careful, there are lots of ways your customers could use this tool to do damage to your data files. It is a programmer tool only.&lt;br /&gt;
&lt;br /&gt;
If you do decide to use it for your end users, be careful how you implement it.&lt;br /&gt;
&lt;br /&gt;
=== Import/Export to CSV ===&lt;br /&gt;
&lt;br /&gt;
You can use FileIO to export your data files to CSV or import from CSV into your data file. To do this, you want to run the data crawler and select the file layout you&#039;re looking for. Then, view it (or press F5 to edit if you want to import something). Click on the Export button and it will ask you to select a file. Once that is selected it will ask a couple other simple questions, and when you&#039;ve specified the options to your satisfaction, click the Export! button. A new CSV file will be created.&lt;br /&gt;
&lt;br /&gt;
Import is even more simple. To import, you must be in Edit mode (press F5 to select the file instead of the enter key) and then simply select the Import button. It will ask you again to choose the file, and then it will ask you if it should update all files by Record Number (if record number is recorded in the CSV file) or by Key (if the file has keys) or to just Add all information to the file. Select what you want and press Import and the CSV file is added to the BR data file.&lt;br /&gt;
&lt;br /&gt;
==== Function Access to Import/Export from your programs ====&lt;br /&gt;
&lt;br /&gt;
You can use the following functions to call the Import and Export functionality from your code.&lt;br /&gt;
&lt;br /&gt;
*[[#fnCSVImport|fnCSVImport]]&lt;br /&gt;
*[[#fnCSVExport|fnCSVExport]]&lt;br /&gt;
&lt;br /&gt;
These functions are intended to give you the ability to use our functionality to write your own import and export routines for your customers, because its not a good idea to let your customers run the Data Crawler.&lt;br /&gt;
&lt;br /&gt;
=== Generate Layout Wizard ===&lt;br /&gt;
&lt;br /&gt;
There is also a Generate Layout Wizard utility in FileIO. This utility is there to help you build your file layouts. It is designed to work with a certain style of BR programming that was common in the 80s and 90s. So if your software is written in a style that opens the file directly, and reads/writes the data to a long series of individual variables, the Generate Layout Wizard is for you.&lt;br /&gt;
&lt;br /&gt;
To use it, start by running FileIO. Then, don&#039;t select a layout - instead, click on the &amp;quot;Generate Layout&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
You&#039;ll see a screen with a bunch of large text boxes, a small grid, and some buttons.&lt;br /&gt;
&lt;br /&gt;
The first thing you want to do is select the &amp;quot;Browse&amp;quot; button and then select a .wb or .br file that contains a program that reads or writes Most of the File.&lt;br /&gt;
&lt;br /&gt;
When you select one, press the Scan All button and it fileio will search the whole program looking first for all the open strings. It will take the file that is opened the most times and then search for all read statements to that file. It will look for the longest read statement and then find the Form statement associated with that Read statement, and any DIM statements for any variables used.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t like the file its chosen, click the &amp;quot;Open Scratch Pad&amp;quot; button to open the temp work file it uses into the program of your choice (I use myEdit for BRS files). Simply select all the open statements for the file you DO want to build off of, then click the Paste button to paste those open statements into the &amp;quot;Open String&amp;quot; list. After that click &amp;quot;Clear All&amp;quot; to erase what it did on the first search and then click &amp;quot;Scan All&amp;quot; again to rescan the program using this new data file.&lt;br /&gt;
&lt;br /&gt;
You may have to help it a bit, but once it has a proper matching open statement, read statement, form statement and dim statements for any arrays used, press the &amp;quot;Generate Layout&amp;quot; button and it will build a layout for that file.&lt;br /&gt;
&lt;br /&gt;
Finally, load the layout it built and clean up anything if you want, and consider adding better descriptions for each of the fields that you know (as it will use the variable names for both the subscripts AND descriptions in the layout).&lt;br /&gt;
&lt;br /&gt;
When you&#039;re all done, click &amp;quot;Done&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Functions to Generate Layouts from your code ====&lt;br /&gt;
&lt;br /&gt;
* [[#fnGenerateLayout_.26_fnWriteLayout|fnGenerateLayout]]&lt;br /&gt;
* [[#fnGenerateLayout_.26_fnWriteLayout|fnWriteLayout]]&lt;br /&gt;
&lt;br /&gt;
=== Code Templates ===&lt;br /&gt;
&lt;br /&gt;
One more tool FileIO has to help is the ability to generate code based on your file layouts.&lt;br /&gt;
&lt;br /&gt;
Run FileIO and this time select a file layout and press &amp;quot;Generate Code&amp;quot;. A window will pop up listing all the &amp;quot;Code Templates&amp;quot; that are available. Select one (and then select a key if it asks you - some templates require extra info). It looks like nothing happened, but the code you generated is now in your clip board. Paste it somewhere and take a look at it!&lt;br /&gt;
&lt;br /&gt;
Code Templates help us to standardize our ways of doing things, which eventually leads to more and more powerful tools we can use. Code Templates also help ensure we use cleaner code by doing some of the busy-work of writing clean code for us.&lt;br /&gt;
&lt;br /&gt;
==== Writing Code Templates ====&lt;br /&gt;
FileIO ships with several basic code templates. If you want to add your own, take a look in the filelay\templates folder (configurable in fileio.ini) and look at basic.brs. Copy it to your own program and then modify it to have your own code templates in it. Write me at gabriel.bakker@gmail.com with any questions. I want to help.&lt;br /&gt;
&lt;br /&gt;
And if you write good code templates, its easy to share them with the BR community. Anyone can download your templates and place them in this folder and they&#039;ll instantly be available for use.&lt;br /&gt;
&lt;br /&gt;
== FileIO Function Reference ==&lt;br /&gt;
&#039;&#039;The FileIO Library contains a number of other useful functions.&#039;&#039; The following functions are available and you are welcome to use them:&lt;br /&gt;
&lt;br /&gt;
=== Primary Functions ===&lt;br /&gt;
&lt;br /&gt;
==== fnOpen ====&lt;br /&gt;
fnOpen is the primary function that opens a file, and it’s used like so:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, DontSortSubs, Path$*255, Mat Descr$, Mat FieldWidths, SupressPrompt, IgnoreErrors, SuppressLog)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note that all of the parameters after MAT Form$ are optional. If you need to specify a parameter in the middle of the optional parameter group, just list zeroes and empty strings for the intervening unused parameters. &lt;br /&gt;
&lt;br /&gt;
*FileName$ - The filename of the file layout for the file you’re reading.&lt;br /&gt;
*MAT F$ - The array that will be used to hold the string data for the file.&lt;br /&gt;
*MAT F – The array that will hold the numeric data for the file.&lt;br /&gt;
*MAT Form$ - An array of form statements.&lt;br /&gt;
*InputOnly – 1 means open for input only. 0 means open for OutIn and open every key file associated with the given data file (this is because all key files need to be open for the keys to be updated on an output) (defaults to 0). Files opened for input process considerably faster than files opened for output. Furthermore when files are opened for input only, alternate key files are &#039;&#039;not&#039;&#039; opened.&lt;br /&gt;
*KeyNum – This tells the function of which key to return the file handle (defaults to 1).&lt;br /&gt;
*DontSortSubs – The function by default, when compiling the Form statement, will sort the string and numeric subs in order to allow for reading the data into an array, and this parameter would turn this functionality off. However, if you are trying to read your data without reading it into an array, you are missing out on some serious efficiencies. You should normally leave this option turned off (0). This is a totally unsupported feature, and should always be set to 0, if it is specified at all.&lt;br /&gt;
*Path$ - The path to your data files. This optional parameter can be passed in by the calling function. It is prefixed to the beginning of the paths given in the file layout files. It is useful when your data files can be in different locations depending on the state of your program.&lt;br /&gt;
*mat Description$ - This optional parameter provides a way to read the description for each field from the original file layout. If the parameter is not provided, no description data will be returned. &lt;br /&gt;
*mat Fieldwidths – This optional parameter will return an array of the calculated display field widths. This number will always be at least large enough to contain the data for this field.&lt;br /&gt;
*SuppressPrompt - This optional parameter can be used to suppress the prompt normally given when fileIO creates a file. It can have three values. A value of 0, the default, uses the setting stored in your FileIO fnSettings routine to determine weather or not to prompt on Creation of a new file. A nonzero value always suppresses the prompt. A value of 1 indicates never to create a file if the file doesn&#039;t exist. A value of 2 automatically creates the file if the file doesn&#039;t exist.&lt;br /&gt;
*IgnoreErrors - Normally when fileio opens a data file, if there are errors trying to open the file, it prints them out to the debug console and pauses so that you can try to find out whats going wrong. If you specify 1 for &amp;quot;IgnoreErrors&amp;quot; it will cause Fileio to log those errors instead, and continue loading your program. This will result in the fnOpen file function returning Zero instead of the opened file number, so if you use IgnoreErrors, you need to test to make sure that fnOpen returned a file number before you try to access the file.&lt;br /&gt;
*SuppressLog - this optional parameter can be used to suppress writing to the log file for this one specific open statement. I use it for files that will be opened all the time, for example, the menu data file on one of my customers systems. Without this boolean parameter, his log file is quickly filled up with useless information any time his employees look at his menu. I specify this optional parameter to suppress logging anything about the menu file so that I can more easily find the actual programs they&#039;ve used when looking in the logfile.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Note: When using fnOpenFile, you really want to call your local function fnOpen, which in turn calls fnOpenFile for you.&#039;&#039;&#039;&#039;&#039;  FnOpenFile is for internal use only.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  Let FFILE=FNOPEN(“FARM”,MAT FARM$,MAT FARM,MAT FORM$,0,2)&lt;br /&gt;
  Let RFILE=FNOPEN(“ROUTE”,MAT ROUTE$,MAT ROUTE,MAT FORM$,1,3)&lt;br /&gt;
  Let CFILE=FNOPEN(“CUSTOMER”,MAT CUSTOMER$,MAT CUSTOMER,MAT FORM$)&lt;br /&gt;
&lt;br /&gt;
assuming:&lt;br /&gt;
  farm.dat has 3 keys: farm.ky1, farm.ky2, farm.ky3&lt;br /&gt;
  route.dat has 4 keys: route.ky1 … route.ky4&lt;br /&gt;
  customer.dat has 2 keys: customer.ky1, customer.ky2&lt;br /&gt;
&lt;br /&gt;
This will perform the following opens and set the following variables:&lt;br /&gt;
&lt;br /&gt;
  OPEN #1: “Name=Farm.Dat, kfname=farm.ky2”,internal,outin,keyed&lt;br /&gt;
  OPEN #2: “Name=Farm.Dat, kfname=farm.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #3: “Name=Farm.Dat, kfname=farm.ky3”,internal,outin,keyed&lt;br /&gt;
  OPEN #4: “Name=Route.Dat, kfname=route.ky3”,internal,input,keyed&lt;br /&gt;
  OPEN #5: “Name=Customer.Dat,kfname=customer.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #6: “Name=Customer.Dat,kfname=customer.ky2”,internal,outin,keyed&lt;br /&gt;
  LET FFILE=1&lt;br /&gt;
  LET RFILE=4&lt;br /&gt;
  LET CFILE=5&lt;br /&gt;
&lt;br /&gt;
This will also resize the arrays, set the form statement, and create all the subscripts to make accessing the data clear and simple, as in the above example. The KEYNUM parameter is where you list the key file you would like to use for reading and writing. The extra keys are opened to ensure that all keys get updated properly when the file is changed.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  DIM FORM$(1),PRICE$(1)*255,PRICE(1),&lt;br /&gt;
  DIM DESCRIPTION$(1)*80,FIELDWIDTHS(1)&lt;br /&gt;
&lt;br /&gt;
  Let PRICEFILE=FNOPEN(“PRICE”,MAT PRICE$,MAT PRICE,MAT FORM$,0,2,0,&amp;quot;&amp;quot;,MAT DESCRIPTION$)&lt;br /&gt;
&lt;br /&gt;
Assuming the Price File layout (filelay\price) contains:&lt;br /&gt;
&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  DUMMY,          Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
 &lt;br /&gt;
This will perform the following opens and set the following variables:&lt;br /&gt;
&lt;br /&gt;
  OPEN #1: “Name=Price.Dat, kfname=Price.ky2”,internal,outin,keyed&lt;br /&gt;
  OPEN #2: “Name=Price.Dat, kfname=Price.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #3: “Name=Price.Dat, kfname=Price.ky3”,internal,outin,keyed&lt;br /&gt;
  let PRICEFILE=1&lt;br /&gt;
  let PR_FARM=1&lt;br /&gt;
  let PR_ITEM=2&lt;br /&gt;
  let PR_GRADE=3&lt;br /&gt;
  let PR_DESCR=4&lt;br /&gt;
  let PR_PRICE=1&lt;br /&gt;
  let PR_COST=2&lt;br /&gt;
  let PR_XOPRICE=3&lt;br /&gt;
  let PR_XOCOST=4&lt;br /&gt;
  let PR_MOPRICE=5&lt;br /&gt;
  let PR_MOCOST=6&lt;br /&gt;
  let PR_VOPRICE=7&lt;br /&gt;
  let PR_VOCOST=8&lt;br /&gt;
  MAT FORM$(1)&lt;br /&gt;
  MAT PRICE$(4)&lt;br /&gt;
  MAT PRICE(8)&lt;br /&gt;
  MAT DESCRIPTION$(12)&lt;br /&gt;
  MAT FIELDWIDTHS(12)&lt;br /&gt;
  let FORM$(1)=CFORM$(”form C 4,C 4,C 4,POS 74,C 30,POS 50,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2”)&lt;br /&gt;
  let Description$(1)= “Farm Code (or blank)”&lt;br /&gt;
  let Description$(2) = “Item Code”&lt;br /&gt;
  let Description$(3) = “Quality”&lt;br /&gt;
  let Description$(4) = “Description of Price Rule”&lt;br /&gt;
  let Description$(5) = “Default Price”&lt;br /&gt;
  let Description$(6) = “Default Cost”&lt;br /&gt;
  let Description$(7) = “Default Christmas Price”&lt;br /&gt;
  let Description$(8) = “Default Christmas Cost”&lt;br /&gt;
  let Description$(9) = “Default Mothers D Price”&lt;br /&gt;
  let Description$(10) = “Default Mothers D Cost”&lt;br /&gt;
  let Description$(11) = “Default Valentine Price”&lt;br /&gt;
  let Description$(12) = “Default Valentine Cost”&lt;br /&gt;
  let FieldWidths(1) = 4&lt;br /&gt;
  let FieldWidths(2) = 4&lt;br /&gt;
  let FieldWidths(3) = 4&lt;br /&gt;
  let FieldWidths(4) = 30&lt;br /&gt;
  let FieldWidths(5) = 8&lt;br /&gt;
  let FieldWidths(6) = 8&lt;br /&gt;
  let FieldWidths(7) = 8&lt;br /&gt;
  let FieldWidths(8) = 8&lt;br /&gt;
  let FieldWidths(9) = 8&lt;br /&gt;
  let FieldWidths(10) = 8&lt;br /&gt;
  let FieldWidths(11) = 8&lt;br /&gt;
  let FieldWidths(12) = 8&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
There are a few things I’d like to point out about the example above. First, you will notice that the form statement jumps around to put all the strings first, and then the numbers last. This is why it has a “POS 74, C 30,POS 50”. Then notice that the subscripts for the string variables are 1 .. 4, and the subscripts for the numbers are 1 .. 8. Finally, the order of the Description and FieldWidth fields also match the sorted positioning of the Form Statement.&lt;br /&gt;
&lt;br /&gt;
The reason that we sort our form statements is so that BR will allow us to read the file into arrays by saying:&lt;br /&gt;
&lt;br /&gt;
  Read #pricefile, using form$(pricefile) : mat price$, mat price&lt;br /&gt;
&lt;br /&gt;
Without resorting, the above statement would give a conversion error as BR attempted to put the PR_PRICE field inside mat price$(4). However, because we have reordered the form statement, we are able to read them safely into two arrays, and then we will be able to use the values without caring what position they are in the file, by simply saying PRICE$(PR_DESCRIPTION) when we want the description, and PRICE(PR_PRICE) when we want the pr_Price field.&lt;br /&gt;
&lt;br /&gt;
Another thing you may notice about the above example is that it gives the calculated display length for the numeric fields as 8, when on the disk (and in the file layout) they are listed as BH 3.2. The reason for this is the program looks at the BH 3, and figures that a number that takes up 3 bytes on disk has a potential maximum size of 256**3 or 16,777,216, and therefore will need up to 8 characters of screen display space to view. &lt;br /&gt;
&lt;br /&gt;
Finally, note that any field with a form statement of X is ignored by the library, except that the blank space is used when building the FORM statement.&lt;br /&gt;
&lt;br /&gt;
==== fnCloseFile ====&lt;br /&gt;
This function will close the specified file number and all keys that were opened with the file.  The purpose of this function is to facilitate the closing of the extra keys that are opened when you open a file for OutIn with the library. There is no need to use this for files opened for input because it is easier to just close the file directly. Secondary keys are not opened by FileIO for files opened for input only. &lt;br /&gt;
&lt;br /&gt;
You must give the function the name of the file layout. It uses this information to determine how many keys were opened, and how many it must therefore close. &lt;br /&gt;
&lt;br /&gt;
Then it basically starts at the file number you gave it, and closes the next X files that were opened with the same file name as this, where X is the number of keys associated with this file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCloseFile(filenumber,filelay$;path$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FileNumber – The filenumber of the file you are trying to close.&lt;br /&gt;
*FileLay$ - The name of the file layout for this file. This is used to determine how many keys the file would have been opened with and therefore how many we now need to close.&lt;br /&gt;
*Path$ - Optional Alternate Path. Use to close files that were opened using the open file&#039;s optional alternate path parameter.&lt;br /&gt;
&lt;br /&gt;
==== fnGetFileNumber ====&lt;br /&gt;
FnGetFileNumber is a simple function to find a valid unused file handle. If you use this function in all of your programs, they will become much more portable, as you will never have to worry about your file handles fighting with each other. The function will return 0 if no free file number was found (but with 999 of them available now, I have never seen it happen).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnGetFileNumber(;X,Count)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*X – This optional parameter will specify where to start looking.&lt;br /&gt;
*Count - This optional parameter will specify how many file numbers to find in a row. If count is 3, then fnGetFileNumber will return the first filenumber in the first gap of three unused file numbers that it finds.&lt;br /&gt;
&lt;br /&gt;
=== File Reading Helper Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions perform various useful calculations to aid in interacting with data files when you&#039;re using fileio.&lt;br /&gt;
&lt;br /&gt;
==== fnBuildKey$ ====&lt;br /&gt;
This function will return the key for a given record in a data file. It actually reads the file layout and builds the key to match the layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnBuildKey$(Layout$, Mat F$, Mat F; Keynum)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the name of the data file to build the key for.&lt;br /&gt;
*Mat F$ - the string array of the file object&lt;br /&gt;
*Mat F - the numeric array of the file object&lt;br /&gt;
*KeyNum - This optional parameter specifies which of the key files in the given layout the key should be built for.&lt;br /&gt;
&lt;br /&gt;
To use this, you want some code like in the following example:&lt;br /&gt;
&lt;br /&gt;
  mat customer$=(&amp;quot;&amp;quot;) : mat Customer=(0)&lt;br /&gt;
  let customer$(cu_name)=CustName$&lt;br /&gt;
  let customer$(cu_phone)=CustPhone$&lt;br /&gt;
  read #customer, using form$(Customer), key=fnBuildKey$(&amp;quot;customer&amp;quot;,mat Customer$,mat Customer,2) : mat Customer$, mat Customer nokey KeyNotFound&lt;br /&gt;
  ! The above code assumes that the second key of the Customer file is based on the Name and Phone fields.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
By using this logic you are able to avoid directly specifying the key in your code - which means that even if the key changes in the future, as long as your code specifies enough information, it will still find the correct key. In our example, even if we dropped the phone number from the key in the future, or even if we expand the length of the Customer Name field, our code would still work and fnBuildKey$ would still build the correct key without us having to look at or change our code again.&lt;br /&gt;
&lt;br /&gt;
This kind of reasoning is central to the fileio system, which, when implemented properly, ensures that you can change your data files in any way you need to in the future, without breaking your existing programs.&lt;br /&gt;
&lt;br /&gt;
==== fnUniqueKey ====&lt;br /&gt;
This function tests to see if a given key is unique to the specified file. This function is very useful for situations where you need to ensure that the user-entered key is unique.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnUniqueKey(Fl,key$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file number of the opened file.&lt;br /&gt;
*Key$ - This is the key to test. If this key is the key for a preexisting record in the file, the function will return false. If this key can not be found in the file, the function will return true.&lt;br /&gt;
&lt;br /&gt;
==== fnMakeUniqueKey$ ====&lt;br /&gt;
This function generates a unique key for a given file. This is useful if you do not care what the key is, but it needs to be unique. I use this function in situations where the user never needs to know what the given key is. &lt;br /&gt;
&lt;br /&gt;
This function reads the key length for the given file. Then it returns a string that is the right length, which is generated by counting in binary until a key is found that does not appear in the file. The first key found for a 4 byte key field would be chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0). If that key was already in use in the file, the function would return chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(1). If that one was also in use, it would then try chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(2), and so on until it found one that wasn’t in use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnMakeUniqueKey$(fl)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – This is the file number of the opened file for the desired key.&lt;br /&gt;
&lt;br /&gt;
==== fnKey$ ====&lt;br /&gt;
This function formats the key for the given file number. All it does is ensure the key is the correct length. You should use fnBuildKey$ instead to properly build the correct key for the record you want to read.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnKey$(FileNumber, Key$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileNumber - the file number we are formatting the key for&lt;br /&gt;
*Key$ - the key we are trying to format.&lt;br /&gt;
&lt;br /&gt;
==== fnNotInFile ====&lt;br /&gt;
This function will determine if a non-key element in a line is unique. It works almost exactly like fnUniqueKey specified above, except that it allows you to enter the subscript value of the element you are checking for uniqueness. You can use this to look for uniqueness in any field, not just in the key field. Additionally, the search engine used by this function looks for a partial match, and will only return true if the given string is not found anywhere in the specified element for the given file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnNotInFile(string$*100,filename$,sub)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - Value to check for uniqueness in this file.&lt;br /&gt;
*Filename$ - This is the name of the file layout of the file you want to check. This file does not have to be open in order for you to search it, because the function will open it for you.&lt;br /&gt;
*Sub – This is the subscript value of the element you are checking.&lt;br /&gt;
&lt;br /&gt;
==== fnSortKeys ====&lt;br /&gt;
This function takes an array of Primary Keys indicating records in the data file, and resorts it into the order you would have expected using one of the other keys for your data file.&lt;br /&gt;
&lt;br /&gt;
For example: Lets say you had a customer file, and the first key was Customer Code and the second key was Customer Last Name. This function would take an array of Customer Codes and sort it into Last Name order.&lt;br /&gt;
&lt;br /&gt;
This function requires the file to already be opened (which is usually the case when you have an array of keys from that file).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnSortKeys(mat Keys$,Layout$,DataFile,mat F$,mat F,mat Form$;KeyNum)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Keys$ - the array of keys. These keys are based on whatever key the file was opened with in DataFile.&lt;br /&gt;
*Layout$ - the file layout for the file.&lt;br /&gt;
*DataFile - the open file number matching the key file that matches mat Keys$.&lt;br /&gt;
*mat F$ - array sized to hold the strings from the data file. This is the array you get back from fnOpen.&lt;br /&gt;
*mat F - array sized to hold the numerics from the data file. This is the array you get back from fnOpen.&lt;br /&gt;
*mat Form$ - array of form statements, that you get back from fnOpen.&lt;br /&gt;
*KeyNum - This is the key that we&#039;ll sort based on. If not given, the first key listed in the layout is assumed.&lt;br /&gt;
&lt;br /&gt;
=== File Reading Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions actually read information from your data file and return it. These functions can be used to simplify the logic in your programs for many common tasks.&lt;br /&gt;
&lt;br /&gt;
==== fnReadAllKeys ====&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record into (a) dynamically dimensioned array(s). For example, I could tell it to give me the Inventory Code for every inventory item in my database in one array, while placing the Inventory Description (name) for each item into the corresponding position in another array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadAllKeys(Fl,mat f$,mat f,mat fm$,sub1,mat out1$;sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – The file handle for the already opened file in question.&lt;br /&gt;
*mat F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array&lt;br /&gt;
*mat out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*mat out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If I wanted to implement the above example, I would say:&lt;br /&gt;
&lt;br /&gt;
  FnReadAllKeys(InventFile,mat Invent$,mat Invent,mat Form$,IN_Code,mat InvtList$,IN_Name,mat InvtNames$)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnReadMatchingKeys ====&lt;br /&gt;
&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record where the key matches the specified key into (a) dynamically dimensioned array(s). This function is the same as the above function except this one will filter the results, returning only those records where the key matches the specified key.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadMatchingKeys(Fl,mat f$,mat f,mat fm$,key$,keysub,sub1,mat out1$;sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*mat F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Key$ - Only records where the key field matches key$ will be returned.&lt;br /&gt;
*Keysub – This tells the function which element is the key element for this particular file number.&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*mat out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnReadAllNewKeys ====&lt;br /&gt;
&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record that isn’t already there into (a) dynamically dimensioned array(s). This function is the same as the above function, except this one will filter the results returning only those records that don’t already exist in the array (eliminating duplicates).&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;FnReadAllNewKeys(Fl,mat f$,mat f,mat fm$,sub1,mat out1$; dont_reset,sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*MAT F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Dont_reset – By default the array will clear the contents of the arrays that are passed in. This Boolean flag will instruct the function to not empty the passed in arrays.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*MAT out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
==== fnReadFilterKeys ====&lt;br /&gt;
&lt;br /&gt;
This function by Mikhail Zheleznov is a modification of the above functions. Like its predecessors, it reads an entire file, populating the specified arrays with data from all or some of the records in the file. The given subscripts specify which fields to return from each record. The key given specifies search criteria for the records. The filter specifies filtering criteria that can be preformed on the data before it is returned. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadFilterKeys(Fl,Mat F$,Mat F,Mat Fm$,Key$,Keyfld,Sub1,Mat Out1$;Filter$,Filter_Sub,Readlarger,Sub2,Mat Out2$, Sub3, Mat Out3$, Sub4,Mat Out4$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*MAT F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Key$ - The key to search for in the read statements&lt;br /&gt;
*Keyfld – the subscript of the key field in the data file. This must match the key field specified in the data file otherwise the function won’t work.&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Filter$ – This optional parameter identifies matches to search for in the records. It works in conjunction with Filter_Sub&lt;br /&gt;
*Filter_Sub – This parameter specifies which field to look for in the records for matches to Filter$. Only records which have Filter$ in the specified field will be returned.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*MAT out2$ - Array in which to return the second (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
*Sub3 – Subscript of the element to return in the third array. This is optional. If it is specified, you must give MAT out3$, or BR will return an error.&lt;br /&gt;
*MAT out3$ - Array in which to return the third (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub3 is given (non-zero). This parameter will not be used if Sub3 is not given or is given as 0.&lt;br /&gt;
*Sub4 – Subscript of the element to return in the fourth array. This is optional. If it is specified, you must give MAT out4$, or BR will return an error.&lt;br /&gt;
*mat out4$ - Array in which to return the fourth (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub4 is given (non-zero). This parameter will not be used if Sub4 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
This function was written by Mikhail Zheleznov for the fileIO library.&lt;br /&gt;
&lt;br /&gt;
==== fnReadDescription$ ====&lt;br /&gt;
&#039;&#039;fnReadDescription$(Fl,Subscript,key$,mat F$,mat F,mat Form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – File Handle for file to use (Route File).&lt;br /&gt;
*Subscript – Index of field in record to use (should be taken from file layout) (RT_NAME, which should equal 2 after opening routefile (unless we change the file layout later)).&lt;br /&gt;
*key$ - Item that should match a key in this file somewhere (in this case it is the route code from the farm record).&lt;br /&gt;
*mat F$ &amp;amp; mat F - Work Variables to hold a file record from the file we are reading they have to be dimensioned properly, which is why we use our colorcat$ and our colorcat for these parameters.&lt;br /&gt;
*mat Form$ - This will need to be our array of form statements, so the function can read the file properly.&lt;br /&gt;
&lt;br /&gt;
Lets take a look at how this function works:&lt;br /&gt;
&lt;br /&gt;
In the example program I used above, I am reading the Color File to get details about each color. The color file contains a colorcat code field, but I want to display the colorcat description. The colorcat file contains a few details about a color category, and it is indexed based on colorcat code:&lt;br /&gt;
&lt;br /&gt;
  route.dat, RT_&lt;br /&gt;
  route.key, CODE&lt;br /&gt;
  recl=512&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE,           Routing Code,                C    6&lt;br /&gt;
  NAME,           Routing Name Description,    C   30&lt;br /&gt;
  MOFT,           T/A/C (truck/air/courier),   C    1&lt;br /&gt;
  SHIPPINGDAY,    Day of Week for Shipping,    C    7&lt;br /&gt;
&lt;br /&gt;
Now, as you know, in the above example, we have already opened the ColorCat File, and we have opened and read a Color record.&lt;br /&gt;
 &lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  30120       read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore&lt;br /&gt;
  30180       LET ccode$=color$(CO_CODE) !:&lt;br /&gt;
              LET Name$=color$(CO_NAME)&lt;br /&gt;
&lt;br /&gt;
Now all that’s left to do is to take the Color File’s ColorCat code and use it to look up the ColorCat File’s description.&lt;br /&gt;
&lt;br /&gt;
  30190 LET ColorCat$ = fnReadDescription$(ColorCatFile, CC_NAME, Color$(CO_CATEGORY),&lt;br /&gt;
    mat ColorCat$, mat ColorCat, mat form$)&lt;br /&gt;
&lt;br /&gt;
==== fnReadUnopenedDescription$ ====&lt;br /&gt;
This function accomplishes the same thing as fnReadDescription except that it opens the data file for you. It is slower then FnReadDescription$, but it is easier to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadUnopenedDescription$(Layout$,key$*255;Field)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are reading&lt;br /&gt;
*key$ - the value of the key field in the record to be read&lt;br /&gt;
*Field - the element of the data file to return. If not given, this defaults to 2, so sometimes it is a good idea to design your data files so that string field number two is a descriptive field, like Name or Description.&lt;br /&gt;
&lt;br /&gt;
This function only works on the first key file for each data file. This function is a convenience function but it is slow because it opens the file and closes it for each call. Opening a file is one of the most time consuming program operations.&lt;br /&gt;
&lt;br /&gt;
==== fnReadNumber ====&lt;br /&gt;
&lt;br /&gt;
fnReadNumber does the same thing that ReadDescription does except it reads a numeric field instead of a description.&lt;br /&gt;
&lt;br /&gt;
Lets take a look at how this function works:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadNumber(Fl,subscript,key$,mat F$,mat F,mat fm$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – File Handle for file to use (Route File).&lt;br /&gt;
*Subscript – Index of field in record to use (should be taken from file layout).&lt;br /&gt;
*Key$ - Item that should match a key in this file somewhere.&lt;br /&gt;
*mat F$ &amp;amp; mat F - Work Variables to hold a file record from the file we are reading. They have to be dimensioned properly by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat Fm$ - This will need to be our array of form statements, so the function can read the file properly.&lt;br /&gt;
&lt;br /&gt;
==== fnReadUnopenedNumber ====&lt;br /&gt;
This function accomplishes the same thing as fnReadNumber except that it opens the data file for you. It is slower then FnReadNumber, but it is easier to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadUnopenedNumber(Layout$,key$*255;Field)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are reading&lt;br /&gt;
*key$ - the key of the record to be read&lt;br /&gt;
*Field - the element of the data file to return. If not given, this defaults to 2, so sometimes it is a good idea to design your data files so that string field number two is a descriptive field, like Name or Description.&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelativeDescription$ ====&lt;br /&gt;
This function is the same as fnReadDescription$ but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelativeDescription$(FileNumber,SubscriptToRead,RecordNumber,mat F$,mat F,mat form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Filenumber - The file number of the open data file&lt;br /&gt;
*SubscriptToRead - The subscript to read&lt;br /&gt;
*RecordNumber - the Record number to read&lt;br /&gt;
*mat F$ and mat F - the arrays to hold the data. They must match the dimensions and should be set with [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat form$ - the forms array is also set by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelUnopenedDescription$ ====&lt;br /&gt;
This is the same as ReadUnopenedDescription$ but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelUnopenedDescription(Layout$,RecordNumber;Field)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*RecordNumber - the record to read&lt;br /&gt;
*Field - the field subscript to read&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelativeNumber ====&lt;br /&gt;
This is the same as fnReadNumber but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelativeNumber(FileNumber,SubscriptToRead,RecordNumber,mat F$,mat f,mat Form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Filenumber - The file number of the open data file&lt;br /&gt;
*SubscriptToRead - The subscript to read&lt;br /&gt;
*RecordNumber - the Record number to read&lt;br /&gt;
*mat F$ and mat F - the arrays to hold the data. They must match the dimensions and should be set with [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat form$ - the forms array is also set by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelUnopenedNumber ====&lt;br /&gt;
This is the same as fnReadUnopenedNumber but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelUnopenedNumber(LayoutName$,RecordNumber;Field)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*RecordNumber - the record to read&lt;br /&gt;
*Field - the field subscript to read&lt;br /&gt;
&lt;br /&gt;
==== fnReadRecordWhere$ ====&lt;br /&gt;
This function returns the record where the given element matches the given value. It does not depend on any key files, and it can be used to locate a record based on any element. However, it loops through the entire data file to do this and it could be a bit slow for large data files. This function opens the file for you, so the file does not have to be already opened.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadRecordWhere$(Layout$,SearchSub,SearchKey$*255,ReturnSub)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are searching&lt;br /&gt;
*SearchSub - Subscript of the element to look in&lt;br /&gt;
*SearchKey$ - The value we are looking for&lt;br /&gt;
*ReturnSub - Subscript of the element to return&lt;br /&gt;
&lt;br /&gt;
=== FileIO Utility Functions ===&lt;br /&gt;
==== fnDataCrawler ====&lt;br /&gt;
This function launches the Data Crawler as a function, so you can make your own programs link to it. Special thanks to Mikhail Zheleznov for turning the DataCrawler into a library function.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDataCrawler(Layout$;SRow$,SCol$,Rows$,Cols$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnDataEdit ====&lt;br /&gt;
This function is the same as fnDataCrawler only it opens a Grid for editing.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDataCrawler(Layout$;SRow$,SCol$,Rows$,Cols$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnShowData ====&lt;br /&gt;
&lt;br /&gt;
This function builds a list or a grid in a floating window that is tied to a data file. It uses the same function that the datacrawler uses, but its much more customizable. All other datacrawler functions are just wrappers for this one.&lt;br /&gt;
&lt;br /&gt;
The first parameter is the only required parameter.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;def library fnShowData(FileLay$;Edit,sRow,sCol,Rows,Cols,KeyNumber,Caption$*127,Path$*255,KeyMatch$*255,SearchMatch$*255,CallingProgram$*255,mat Records,mat IncludeCols$,mat IncludeUI$,mat ColumnDescription$,mat ColumnWidths,mat ColumnForms$,DisplayField$*80,mat FilterFields$,mat FilterForm$,mat FilterCompare$,mat FilterCaption$,mat FilterDefaults$,mat FilterKey)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileLay$ - the file layout you want to display&lt;br /&gt;
*Edit - 1 for Edit (Grid) and 0 for View (Listview)&lt;br /&gt;
*sRow, sCol - the start position. if not given, its centered. If given but out of bounds, they&#039;ll be automatically adjusted to fit the grid on the screen.&lt;br /&gt;
*Rows, Cols - the size. If not given, defaults to fullscreen. If given but not big enough to fit the UI elements you request, they&#039;re automatically adjusted to fit everthing.&lt;br /&gt;
*KeyNumber - the Key to use when reading the data, used with other parameters. If not given, the file is read Relative for faster performance. Required if KeyMatch$ is given.&lt;br /&gt;
*Caption$ - the Caption to display, defaults to FileIO&#039;s Datacrawler&lt;br /&gt;
*Path$ - Alternate path to use for data files (Prepended to the name found in the layout)&lt;br /&gt;
*KeyMatch$ - Show only records that match this key. You can use Partial Keys. If this parameter is given, you must also give KeyNumber (above).&lt;br /&gt;
*SearchMatch$ - Show only records that contain this substring in them anywhere&lt;br /&gt;
*CallingProgram$ - used for logging purposes, pass in the system function Program$&lt;br /&gt;
*mat Records - Show only these records in the Grid. Use it to control exactly what the user sees.&lt;br /&gt;
*mat IncludeCols$ - Show only these columns. These column names must match the subscript names from the file layout.&lt;br /&gt;
*mat IncludeUI$ - Which UI Options to show. Build this array with one element for each optional UI element to include. Explanations of UI elements follow:&lt;br /&gt;
**&amp;quot;ColumnsButton&amp;quot; - adds a Select Columns button that the user can use to modify which columns appear on the list.&lt;br /&gt;
**&amp;quot;ExportButton&amp;quot; - adds an Export to CSV button that exports the data to a CSV file.&lt;br /&gt;
**&amp;quot;ImportButton&amp;quot; - adds an Import from CSV button that imports from the CSV file.&lt;br /&gt;
**&amp;quot;AddButton&amp;quot; - adds a button that can be used to add records to the data file.&lt;br /&gt;
**&amp;quot;SaveButton&amp;quot; - adds a button allowing the user to save changes&lt;br /&gt;
**&amp;quot;DeleteButton&amp;quot; - adds a button allowing the user to delete a row&lt;br /&gt;
**&amp;quot;KeyButton&amp;quot; - adds a button allowing the user to jump to a specified position by key or by record number (depending on if the file is opened keyed or not)&lt;br /&gt;
**&amp;quot;QuitButton&amp;quot; - adds a Quit button to the screen (the Esc key also quits)&lt;br /&gt;
**&amp;quot;Search&amp;quot; - adds a case insensitive search box to the screen.&lt;br /&gt;
**&amp;quot;Border&amp;quot; - adds a border around the screen&lt;br /&gt;
**&amp;quot;Caption&amp;quot; - adds a caption. (If you specify a caption, this is automatically turned on. If you don&#039;t specify a caption but turn on caption here, then FileIO uses the default FileIO data crawler caption.&lt;br /&gt;
**&amp;quot;Recl&amp;quot; - adds the Recl to the caption&lt;br /&gt;
**&amp;quot;Position&amp;quot; - adds the positions to the field descriptions in the column headings.&lt;br /&gt;
*mat ColumnDescription$ - Show these captions. If blank, use the descriptions from the layout&lt;br /&gt;
*mat ColumnWidths - Use these widths for the data, if not given, calculate from the file layout&lt;br /&gt;
*mat ColumnForms$ - Display Format for the data, including DATE and FMT and PIC&lt;br /&gt;
*mat DisplayField$ - Counter Field to display on the Loading Window. If its a field with an associated DATE ColumnForms$ value, that column form will be used when displaying the Counter Field. It can be any of the following:&lt;br /&gt;
**REC - this will display the current &amp;quot;REC/LREC&amp;quot; data in the loading window.&lt;br /&gt;
**READCOUNT - this will display the &amp;quot;Record Count / LREC&amp;quot; in the loading window.&lt;br /&gt;
**FINDCOUNT - this will display the number of records that match the current search criteria by itself in the loading window.&lt;br /&gt;
**A Field Name - one of your field names will display that field value in the loading window&lt;br /&gt;
**A string literal - anything else will display as a string in the loading window, so you could put something like &amp;quot;Loading, please wait&amp;quot; here and it will display.&lt;br /&gt;
*mat FilterFields$ - Contains the subscript of the field to compare to&lt;br /&gt;
*mat FilterForm$ - Contains the format of the field to compare to&lt;br /&gt;
*mat FilterCompare$ - Contains the comparison type (&amp;quot;&amp;lt;&amp;gt;&amp;quot; or &amp;quot;&amp;gt;&amp;quot; or &amp;quot;=&amp;quot; or &amp;quot;&amp;gt;=&amp;quot; or &amp;quot;*&amp;quot;) (* means do a substring search)&lt;br /&gt;
*mat FilterCaption$ - The caption for the filter box&lt;br /&gt;
*mat FilterDefaults$ - The default value for the filter information&lt;br /&gt;
*mat FilterKey - The action to use when filtering the data this way (0 means simple exclude, 1 means start here, -1 means stop here)&lt;br /&gt;
**The final five arrays can be used to add user filter boxes to the data grid. You need one element in each array for every custom user filter box on the screen.&lt;br /&gt;
&lt;br /&gt;
==== fnCSVImport ====&lt;br /&gt;
&lt;br /&gt;
This function calls the FileIO Import routine, the same one that you get from the Datacrawlers Import Button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCsvImport(Layout$*64;SuppressDialog,FileName$*300,ImportModeKey)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout to import into&lt;br /&gt;
*SupressDialog - 1 to Supress the Import Dialog&lt;br /&gt;
*FileName$ - the name of the CSV file (Required if Dialog is Suppressed)&lt;br /&gt;
*ImportModeKey - the Import Mode Key (Required if Dialog is Suppressed)&lt;br /&gt;
**-1 - Add all records to the file&lt;br /&gt;
**0 - Update by Record Number (The file must contain a RecNum column and it must be first)&lt;br /&gt;
**1+ - Any positive number means Update by that Key (as listed in the layout).&lt;br /&gt;
&lt;br /&gt;
==== fnCSVExport ====&lt;br /&gt;
&lt;br /&gt;
This function exports a data file to a CSV file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCsvExport(Layout$*64;SuppressDialog,Filename$*300,IncludeRecNums,KeyNumber,StartKey$,KeyMatch$,Startrec,mat Records,SearchMatch$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The File Layout to Export&lt;br /&gt;
*SuppressDialog - (1 to Suppress the Export Dialog, 0 to show it)&lt;br /&gt;
*Filename$ - the output file name (Required if SuppressDialog is 1)&lt;br /&gt;
*IncludeRecNums - Include a column with the Record Numbers in it&lt;br /&gt;
*KeyNumber - Use this key when reading the data for export&lt;br /&gt;
*StartKey$ - Start with the record that matches StartKey$&lt;br /&gt;
*KeyMatch$ - Export only the record(s) that match KeyMatch$&lt;br /&gt;
*StartRec - Start with this Record Number&lt;br /&gt;
*mat Records - Export only these records&lt;br /&gt;
*SearchMatch$ - Export only records containing this search string anywhere in them&lt;br /&gt;
&lt;br /&gt;
==== fnGenerateLayout &amp;amp; fnWriteLayout ====&lt;br /&gt;
&lt;br /&gt;
This function calls on the Generate File Layout Wizard to generate and save the layout indicated by the parameters you give it. You must give it the same valid parameters that you would have come up with if you worked through the layout wizard the normal way, by running FileIO directly and choosing &amp;quot;Generate Layout&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can also bypass the automatic parsing and generate a layout by specifying all the data directly and using fnWriteLayout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnGenerateLayout(mat OpenStrings$, ReadString$*999, FormString$*20000, DimString$*999; DisplayFile)&#039;&#039;&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat OpenString$ - array of all the open strings for the given file from one of your old programs.&lt;br /&gt;
*mat ReadString$ - solid read statement from one of your old programs reading the entire record, (or at least everything you want in the layout).&lt;br /&gt;
*mat FormString$ - the form statement that goes with the ReadString$ (practice using the Generate Layout Wizard the normal way for details)&lt;br /&gt;
*mat DimString$ - the string containing Dim statements for each array mentioned in ReadString$. We need this to know how big the arrays are.&lt;br /&gt;
*DisplayFile - if True (1), it will Display the new layout in notepad when its done creating it. If false (0), it will simply create the file.&lt;br /&gt;
&lt;br /&gt;
fnGenerateLayout takes all the above information and parses it into a layout, then calls fnWriteLayout to actually write the layout.&lt;br /&gt;
&lt;br /&gt;
If you already know the information you want to put in the layout, its more direct to call fnWriteLayout below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnWriteLayout(Name$,FileName$*127,VER,PRE$,MAT KFNAME$,MAT KDESCRIPTION$,MAT SUBS$,MAT DESCR$,MAT FORM$;RECL,MAT EXTRA$,DISPLAYFILE)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Name$ - the name of the new layout&lt;br /&gt;
*FileName$*127 - the name of the data file&lt;br /&gt;
*Ver - the version of the data file&lt;br /&gt;
*Pre$ - the prefix to use for the data file&lt;br /&gt;
*mat KfName$ - array of all the keys for the file&lt;br /&gt;
*mat Kdescription$ - array of the subscripts that each key is based on&lt;br /&gt;
*mat Subs$ - the subscript for each field in the file&lt;br /&gt;
*mat Descr$ - the descriptions for each field in the file&lt;br /&gt;
*mat Form$ - the form specs for each field in the file&lt;br /&gt;
*Recl - (optional) the record length of the file&lt;br /&gt;
*mat Extra$ - (optional) Additonal Information for each field in the file, placed in the Comments column of the new layout. This column is ignored by standard fileio processing.&lt;br /&gt;
DisplayFile - if True, open the file in Notepad after it has been created.&lt;br /&gt;
&lt;br /&gt;
=== File System Utility Functions ===&lt;br /&gt;
These functions perform other tasks that aid with interacting with the file system.&lt;br /&gt;
&lt;br /&gt;
==== fnGetFileDateTime$ ====&lt;br /&gt;
This does a directory listing to determine the Last Modified Date and Time of the given file. You pass it a file name, not a file layout, and it can be used on any file. Its not limited to BR internal files.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let FileDate$=fnGetFileDateTime$(Filename$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnCopyFile ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCopyFile(FromFile$*255,ToFile$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FromFile$ - The file to copy.&lt;br /&gt;
*ToFile$ - The destination file name including path.&lt;br /&gt;
&lt;br /&gt;
This function copies any file, by opening it as an external file and reading and writing the data to the destination file. The advantage of this technique, over using the BR copy command, is this routine is more reliable when run on client server where you may be transferring large files from one side to the other over the internet.&lt;br /&gt;
&lt;br /&gt;
This fnCopyFile also has a progress bar that displays as the file is transferred, so the user knows your software is busy.&lt;br /&gt;
&lt;br /&gt;
This function works over Client Server. Under Client Server, specify @: at the beginning of your filename, to specify that the file is on the client. If the file is on the server, simply leave the @: off. See the chapter on [[Copy#Client_Server|using BR&#039;s copy command under Client Server]] for more details on the &amp;quot;@:&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This function&#039;s parameters and syntax are modeled off of the built in BR copy command, and like that one, this should work for local transfers, LAN transfers, or even internet transfers. This function will work better for internet transfers then the built in BR Copy Command, however. &lt;br /&gt;
&lt;br /&gt;
==== fnCopyDataFiles ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCopyDataFiles(DestinationFolder$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*DestinationFolder$ - the folder to copy your data files to.&lt;br /&gt;
&lt;br /&gt;
This function reads your file layouts and makes a copy of every data file (and key file) in your system to the destination folder, utilizing fnCopyFile above, for better performance and reliability when running over the internet, as well as a progress bar for each individual file.&lt;br /&gt;
&lt;br /&gt;
It also displays a listview while its copying so you can watch the progress while its transferring your data files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This can be used for making backups of your BR data, or for transferring the latest data onto a laptop for access to it while you&#039;re on the road away from the internet.&lt;br /&gt;
&lt;br /&gt;
==== fnReIndex ====&lt;br /&gt;
&lt;br /&gt;
This function reindexes a single data file&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReIndex(DataFile$*255;CallingProgram$*255,IndexNum,Path$*25)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Datafile$ - the file layout of the file to index&lt;br /&gt;
*CallingProgram$ - used for logging, pass Program$ in here&lt;br /&gt;
*IndexNum - The index to rebuild - if not given, rebuilds all indexes&lt;br /&gt;
*Path$ - the optional alternate path to use for rebuilding the data file.&lt;br /&gt;
&lt;br /&gt;
==== fnReIndexAllFiles ====&lt;br /&gt;
&lt;br /&gt;
This function reindexes all your data files. It doesn&#039;t require any parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReIndexAllFiles&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnUpdateFile ====&lt;br /&gt;
This function checks and Updates a data file if it needs to be updated, by opening and then closing the data file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnUpdateFile(FileLayout$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileLayout$ - The name of the file to update&lt;br /&gt;
&lt;br /&gt;
==== fnRemoveDeletes ====&lt;br /&gt;
&lt;br /&gt;
This function, written by Susan Smith, removes deleted records by copying the file with the -D option.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnRemoveDeletes(LayoutName$*255;Path$*255,CallingProgram$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*LayoutName$ - the file layout&lt;br /&gt;
*Path$ - Optional Alternate Path&lt;br /&gt;
*CallingPRogram$ - used for logging, pass Program$ in here&lt;br /&gt;
&lt;br /&gt;
=== Layout Interrogation ===&lt;br /&gt;
Layout interrogation functions are provided for convenience and to enable future dictionary changes without disrupting any programs that interrogate it.&lt;br /&gt;
&lt;br /&gt;
==== fnMakeSubProc ====&lt;br /&gt;
This function obtains the subscript assignments that were assigned by fnOpen according to the file layout. The fnMakeSubProc$ routine obtains the subscript assignments without actually opening the file. This is useful when a file record is passed as arrays into a library function in another program, or when you chained to another program and you need to know how to reach the data in the arrays without actually reopening the file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnMakeSubProc(filelay$;mat Subscripts$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FileLay$ - The name of the file layout from which to read the subscripts.&lt;br /&gt;
*mat Subscripts$ - If you give this optional array, fnMakeSubProc passes the subscripts back in this array rather then in the subs.$$$ file. This is much faster and helps avoid sharing conflicts.&lt;br /&gt;
&lt;br /&gt;
When this routine returns, you can set the subscripts in your program by executing every element of the Subscripts$ array in a for/next loop.&lt;br /&gt;
&lt;br /&gt;
If you did not pass in a subscripts array, then the a procedure file named subs.$$$ is created. If you proc that file, the proper subscripts will be set.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutArrays ====&lt;br /&gt;
This function reads the fields in a file layout into arrays. You call it like the following&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLayoutArrays(filelay$,&amp;amp;prefix$;mat SSubs$, mat NSubs$, mat SSpec$, mat NSpec$,mat SDescription$, mat NDescription$,Mat Spos,Mat Npos)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*filelay$ - the name of the layout to read&lt;br /&gt;
*prefix$ - the return value for the prefix for the file&lt;br /&gt;
*mat SSubs$ - the return value for all the string subscripts in the layout&lt;br /&gt;
*mat NSubs$ - the return value for the numeric subscripts in the layout&lt;br /&gt;
*mat SSpec$ - the return value for the string fields specs&lt;br /&gt;
*mat NSpec$ - the return value for the numeric fields specs&lt;br /&gt;
*mat SDescription$ - the return value for the Descriptions of the String Specs&lt;br /&gt;
*mat NDescription$ - the return value for the Descriptions of the Numeric Specs&lt;br /&gt;
*mat SPos - the return value for the starting positions of the String Specs&lt;br /&gt;
*mat NPos - the return value for the starting positions of the Numeric Specs&lt;br /&gt;
&lt;br /&gt;
This function call would read the fields from the layout in filelay$, and it would return the prefix to prefix$. The Subs would be returned in mat SSubs$ and mat NSubs$.&lt;br /&gt;
&lt;br /&gt;
The Spec statements are returned in mat SSpec$ and mat NSpec$ and the Descriptions are returned in mat SDescription$ and mat NDescription$. The start positions on disk of each element are returned in mat SPos and mat NPos.&lt;br /&gt;
&lt;br /&gt;
All the arrays are optional. If you don’t pass them the information they are supposed to record is simply not returned.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutHeader ====&lt;br /&gt;
This function reads the header for a given file layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLayoutHeader(Layoutname$*255;&amp;amp;Filename$,Mat Keys$,Mat KeyDescription$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*LayoutName$ - Name of the layout to read&lt;br /&gt;
*Filename$ - The file name read from the layout&lt;br /&gt;
*Mat Keys$ - Array to be populated with the list of keys for the file&lt;br /&gt;
*Mat KeyDescription$ - Key Description String returned from the file&lt;br /&gt;
&lt;br /&gt;
==== fnReadEntireLayout ====&lt;br /&gt;
This function reads the entire layout by calling fnReadLayoutHeader and fnReadLayoutArrays.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadEntireLayout(Layoutname$*255;&amp;amp;Filename$,&amp;amp;Prefix$,Mat Keys$,Mat KeyDescription$,Mat Ssubs$,Mat Nsubs$,Mat Sspec$,Mat Nspec$,Mat Sdescription$,Mat Ndescription$,Mat Spos,Mat Npos)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*LayoutName$ - Name of the layout to read&lt;br /&gt;
*Filename$ - The file name read from the layout&lt;br /&gt;
*prefix$ - the return value for the prefix for the file&lt;br /&gt;
*Mat Keys$ - Array to be populated with the list of keys for the file&lt;br /&gt;
*Mat KeyDescription$ - Key Description String returned from the file&lt;br /&gt;
*mat SSubs$ - the return value for all the string subscripts in the layout&lt;br /&gt;
*mat NSubs$ - the return value for the numeric subscripts in the layout&lt;br /&gt;
*mat SSpec$ - the return value for the string fields specs&lt;br /&gt;
*mat NSpec$ - the return value for the numeric fields specs&lt;br /&gt;
*mat SDescription$ - the return value for the Descriptions of the String Specs&lt;br /&gt;
*mat NDescription$ - the return value for the Descriptions of the Numeric Specs&lt;br /&gt;
*mat SPos - the return value for the starting positions of the String Specs&lt;br /&gt;
*mat NPos - the return value for the starting positions of the Numeric Specs&lt;br /&gt;
&lt;br /&gt;
==== fnReadSubs ====&lt;br /&gt;
This function reads the subscripts from a layout into Subs arrays.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadSubs(Layout$,mat SSubs$,mat NSubs$,&amp;amp;Prefix$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - the file layout name&lt;br /&gt;
*mat SSubs$ - the String Subscript Names&lt;br /&gt;
*mat NSubs$ - the Number Subscript Names&lt;br /&gt;
*Prefix$ - the files Prefix&lt;br /&gt;
&lt;br /&gt;
==== fnReadKeyFiles ====&lt;br /&gt;
This function reads the list of key files from the layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadKeyFiles(Layout$,mat Keys$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*mat Keys$ - output array, the keys are returned here.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayouts ====&lt;br /&gt;
This function reads the file layout folder and returns all the applicable layouts in the passed in array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadLayouts(mat Dirlist$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Mat Dirlist$ - After running the function, mat Dirlist$ will contain a list of all the file layouts that FileIO can find.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutPath$ ====&lt;br /&gt;
This function doesn&#039;t actually interrogate your layouts. Instead, it interrogates your settings and returns the path specified for your layout files. This would usually be &amp;quot;filelay\&amp;quot; but you can change it in [[#fnSettings|fileio.ini.]]&lt;br /&gt;
&lt;br /&gt;
It has no parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let Path$=fnReadLayoutPath$&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnDoesLayoutExist ====&lt;br /&gt;
This function returns true if the given file layout exists. It returns false if the layout does not exist.&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;FnDoesLayoutExist(layout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - Layout to test for&lt;br /&gt;
&lt;br /&gt;
==== fnReadForm$ (uncompiled) ====&lt;br /&gt;
Sometimes you need to know the original form statement that fileio is using to read your data file, most often when you&#039;re debugging your file layout, and you&#039;re getting some problem when reading the file. The form statement that fileio normally returns is compiled using CFORM$ to save space in the array, and to make the execution of your read statements faster. You can use this function to return the original form statement for the file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let FormStatement$=fnReadForm$*10000(FileLayout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remember to dimension FormStatement to something huge! fnReadForm$ can return up to 10,000 characters.&lt;br /&gt;
&lt;br /&gt;
==== fnReadFormAndSubs ====&lt;br /&gt;
&lt;br /&gt;
This function does the same as above but it also reads the subscripts from the file into an array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let fnReadFormAndSubs(Layout$,mat Subs$,&amp;amp;ReadForm$,&amp;amp;StringSize,&amp;amp;NumberSize)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note that unlike most of our functions, all the above parameters are required.&lt;br /&gt;
&lt;br /&gt;
The layout is the layout you&#039;re interrogating. The Array will be populated with the subscripts after the function. The ReadForm$ variable will be filled with the form statement for the file. Remember to dimension it large enough. StringSize and NumberSize will contain the number of string fields and numeric fields in the file.&lt;br /&gt;
&lt;br /&gt;
Mat Subs$ will be returned, strings first, numbers last, matching the form statement that is returned. So Subs$(1) is the first string subscript and Subs$(StringSize+1) is the first Numeric subscript.&lt;br /&gt;
&lt;br /&gt;
=== Other Useful Functions (non-layout related) ===&lt;br /&gt;
&lt;br /&gt;
==== fnAskCombo ====&lt;br /&gt;
&lt;br /&gt;
Opens a window with a combo box and returns the users selection.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnAskCombo$*255(mat Description$;Caption$*60,Default$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Description$ - contains the combo box choices&lt;br /&gt;
*Caption$ - contains the optional caption for the window&lt;br /&gt;
*Default$ - the text of the item in mat Description$ that you want to be selected by default&lt;br /&gt;
&lt;br /&gt;
==== fnSendEmail ====&lt;br /&gt;
&lt;br /&gt;
This function sends an email and an optional attachment to the email address specified.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnSendEmail(Emailaddress$*255,Message$*10000;Subject$*255,Invoicefile$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*EmailAddress$ - the Destination Email Address&lt;br /&gt;
*Message$ - the Message$ to send&lt;br /&gt;
*Subject$ - the subject&lt;br /&gt;
*InvoiceFile$ - the filename of a file to attach. This is the BR filename (the function automatically converts it to an OS Filename.)&lt;br /&gt;
&lt;br /&gt;
The function returns 1 when the email was sent successfully, or 0 if it wasn&#039;t sent successfully.&lt;br /&gt;
&lt;br /&gt;
In order to use this function, you must have the emailcfg file layout in your layouts folder and you must have a copy of SendEmail.exe which is free and can be downloaded from the internet. Both of these files are included with the latest update of fileio.&lt;br /&gt;
&lt;br /&gt;
You also have to configure fileio with the authentication information for your email server.&lt;br /&gt;
&lt;br /&gt;
To configure your email server, simply run FileIO to get the data crawler, then select the emailcfg file layout and press F5 to edit it. Add a row if the file is empty.&lt;br /&gt;
&lt;br /&gt;
Simply fill in the information the file is asking for in the appropriate fields and save the data, and then test sending an email to make sure it worked.&lt;br /&gt;
&lt;br /&gt;
==== fnClientEnv$ ====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a Windows Environment Variable on the client under Client Server.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnClientEnv$*255(EnvKey$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*EnvKey$ is the name of the Windows Environment Variable to check on the client.&lt;br /&gt;
&lt;br /&gt;
The function returns the value of the entered environment variable.&lt;br /&gt;
&lt;br /&gt;
==== fnEmpty &amp;amp; fnEmptyS ====&lt;br /&gt;
These functions are for testing optional arrays that may or may not have been passed into your function. BR will give an error if your code attempts to use an optional array that wasn&#039;t passed in, so you can use these functions to test if the user actually passed in the optional array or not.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnEmpty(mat Numeric)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnEmptyS(mat String$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  def fnSomeFunction(String$,mat Array$; mat OptionalArray)&lt;br /&gt;
     if ~fnEmpty(mat OptionalArray) then&lt;br /&gt;
        ! mat Optional array was given, process it here.&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
==== fnReadScreenSize ====&lt;br /&gt;
This function reads the screen size of the given window (or window 0 if a window wasn&#039;t passed.) This is useful for centering a window on the screen, or for making sure window 0 is big enough for the child window you&#039;re trying to create.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadScreenSize(&amp;amp;Rows,&amp;amp;Cols;ParentWindow)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The screen size is returned in the first two parameters, and the third parameter tells the function which window to interrogate. If not given, it assumes window 0.&lt;br /&gt;
&lt;br /&gt;
==== fnBuildProcFile ====&lt;br /&gt;
This function builds a proc file to be executed later. This function and the next simplify the process of executing code in a proc file. It can even be used to spawn a new session of BR.&lt;br /&gt;
&lt;br /&gt;
To use it, call fnBuildProcFile one or more times and specify some lines of code to execute.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnBuildProcFile(Command$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;load Program2$&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;run&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;system&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  let fnRunProcFile(1)&lt;br /&gt;
&lt;br /&gt;
==== fnRunProcFile ====&lt;br /&gt;
&lt;br /&gt;
This function spawns a new copy of BR and in it, runs the proc file that you&#039;ve previously built using fnBuildProcFile (above).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; fnRunProcFile(;NoWait) &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The optional parameter &amp;quot;NoWait&amp;quot; causes the other session to spawn and run in a new thread. If you don&#039;t specify NoWait, the current session pauses and waits for the other session to close before proceeding.&lt;br /&gt;
&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;load Program2$&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;run&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;system&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  let fnRunProcFile(1)&lt;br /&gt;
&lt;br /&gt;
==== fnLog &amp;amp; fnErrLog ====&lt;br /&gt;
These next two functions are functions to aid in logging. When you call either of these two functions, you give them a string that you wish to log. They will open the FileIO Log File and add a record to the end of it containing some user information such as login_name and session$, and the string that you specified. FnErrLog does the same thing as fnLog except it also logs the Error Number and the Line.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnLog(string$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - the Log Message&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnErrLog(String$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - the Log Message&lt;br /&gt;
&lt;br /&gt;
==== fnLogArray ====&lt;br /&gt;
&lt;br /&gt;
This function logs the given arrays to the log file, logging each field in the arrays. Its useful for recording, for example, an entire data record that is about to be written to a data file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnLogarray(mat F$,mat f;Message$*512,CallingProgram$*255)&#039;&#039;&lt;br /&gt;
The first two parameters, of course, are the array to log. The third parameter is an optional message to be recorded along with the array, and the fourth optional parameter is the CallingProgram$ to save in the log along with the message. (The CallingProgram$ parameter can usually be passed as the system function Program$)&lt;br /&gt;
&lt;br /&gt;
==== fnSetLogChanges ====&lt;br /&gt;
This function works in conjunction with the next function, and they&#039;re for recording just what changed in a data file. When the file is read, you call fnSetLogChanges and record the &amp;quot;before&amp;quot; picture of the file record.&lt;br /&gt;
&lt;br /&gt;
After changes have been made and saved back to disk, you can call fnLogChanges below to record the actual changes.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnSetLogChanges(mat F$,mat F)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnLogChanges ====&lt;br /&gt;
This function is the other half of the function above. It compares the given arrays with the ones set previously in the above function and checks for changes. Then it generates a log message recording information about just the items that changed.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnLogChanges(mat F$,mat F;Message$*1024,CallingProgram$*255,Layout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You need to pass in the same two arrays as before, but this time the modified versions of them.&lt;br /&gt;
&lt;br /&gt;
You can also optionally pass a 1024 byte log message to record with the log entry.&lt;br /&gt;
&lt;br /&gt;
CallingProgram$ again should be passed as the system internal function Program$.&lt;br /&gt;
&lt;br /&gt;
The final parameter allows the passing of a Layout$. If you pass a Layout$, that layout is read and the subscripts are used when making the log message of changes, so that its easier to read. If you pass a layout, it will identify the changed fields by name. If you don&#039;t it will identify those fields by relative position number.&lt;br /&gt;
&lt;br /&gt;
==== fnViewLogFile ====&lt;br /&gt;
All of the above functions store the information by default into a BR internal file defined in the filelay\logfile layout.&lt;br /&gt;
&lt;br /&gt;
The fnViewLog function uses fnShowData to call the Data Crawler to display the FileIO Log File in a searchable listview.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnViewLogFile&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnReadLockedUsers ====&lt;br /&gt;
&lt;br /&gt;
This function returns a list of all users using the locked data file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLockedUsers(mat Users$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Users$ - the list of users is returned here&lt;br /&gt;
&lt;br /&gt;
==== fnDisplayLength ====&lt;br /&gt;
This function calculates the display length of a field based on its form spec.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDisplayLength(Spec$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Spec - the Form Spec to return the display length of.&lt;br /&gt;
&lt;br /&gt;
==== fnLength ====&lt;br /&gt;
This function calculates the length on disk of a field based on its form spec.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnLength(Spec$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Spec$ - the Form Spec to return the display length of.&lt;br /&gt;
&lt;br /&gt;
== FileIO fnSettings (Global Settings Code) ==&lt;br /&gt;
&lt;br /&gt;
The FileIO library can be made to implement certain policies across the board.  These are established by creating a file called fileio.ini and typing statements like the following into it. This file is &amp;quot;PROCed&amp;quot;, so you don&#039;t want to put line numbers in it.&lt;br /&gt;
&lt;br /&gt;
Anything you don&#039;t specify in fileio.ini will take its default value, shown below. So you only need to specify the items that you want to be different.&lt;br /&gt;
&lt;br /&gt;
Note, for the boolean settings below, 1 denotes TRUE and 0 denotes FALSE.&lt;br /&gt;
&lt;br /&gt;
  let EnforceDupkeys=1                   ! Enforce that key number 1 is unique key&lt;br /&gt;
  let Defaultfilelayoutpath$=&amp;quot;filelay\&amp;quot;  ! Path To Your File Layouts&lt;br /&gt;
  let Promptonfilecreate=1               ! Ask User Before Creating New Files&lt;br /&gt;
  let Createlogfile=0                    ! Use Logging&lt;br /&gt;
  let StartFileNumber=1                  ! Set above 300 to avoid conflicts with legacy programs.&lt;br /&gt;
  let CheckIndex=0                       ! Automatically Verify Indexes (slow)&lt;br /&gt;
  let CompressColumns=0                  ! Shrink or Expand Columns in Data Crawler by Default&lt;br /&gt;
  let MaxColWidth=20                     ! Max Default Column Width in Data Crawler&lt;br /&gt;
  let LogLibrary$=&amp;quot;&amp;quot;                     ! Defaut Log Library, defaults to None&lt;br /&gt;
  let LogLayout$=&amp;quot;&amp;quot;                      ! Log file layout, defaults to Internal File&lt;br /&gt;
  let AnimateDatacrawler=1               ! Use ScreenIO Animation for Datacrawler&lt;br /&gt;
  let TemplatePath$=&amp;quot;filelay\template\&amp;quot;  ! Default Template Path&lt;br /&gt;
  let IgnoreLayouts$=&amp;quot;&amp;quot;                  ! List any Ignore Layouts here.&lt;br /&gt;
  let CloseFileSimple=0                  ! Use simple comparison for fnCloseFile&lt;br /&gt;
&lt;br /&gt;
==== EnforceDupkeys ====&lt;br /&gt;
&lt;br /&gt;
Turn on the EnforceDupkeys option to force that the first key listed in your file layouts is a unique key. FileIO will generate the standard BR error for Dupkeys when attempting to create indexes if it is not unique.&lt;br /&gt;
&lt;br /&gt;
==== DefaultFileLayoutPath$ ====&lt;br /&gt;
&lt;br /&gt;
Use the DefaultFileLayoutPath option to specify the path from your programs to your file layout folder. The default is &amp;quot;filelay\&amp;quot;. Use this setting if you want to place your file layouts in another folder from the default.&lt;br /&gt;
&lt;br /&gt;
==== PromptOnFileCreate ====&lt;br /&gt;
&lt;br /&gt;
Use the PromptOnFileCreate setting to cause FileIO to display a message box whenever it is attempting to create a new file. This happens during the automatic update procedure, as well as during any attempt to access a file that does not exist. This setting should be turned off in your live system, and only turned on for development purposes. If you use the message box to cancel creating of the new file, then the file is not created, and fileIO or your application will most likely give an error when you attempt to actually access the new file.&lt;br /&gt;
&lt;br /&gt;
It can be useful during development to make sure that you don&#039;t accidentally create the wrong files, due to an incorrectly specified path or a typeo in the filename in the layout file. However, in a live system, these things have already been tested, and you generally want the default behavior, because you don&#039;t want your users to have the ability to cancel the normal operation of FileIO.&lt;br /&gt;
&lt;br /&gt;
==== CreateLogFile ====&lt;br /&gt;
&lt;br /&gt;
Use this option to specify weather or not to use the FileIO log file. If it is turned on, a log file called FileIO.log in the current directory is created with entries listing all attempts to open a file, automatically update one, or automatically update your indexes.&lt;br /&gt;
&lt;br /&gt;
==== StartFileNumber ====&lt;br /&gt;
&lt;br /&gt;
Use this option to set the starting file number that the fnGetFileNumber and the fnOpen functions use to search for available file numbers. This is so that if you have certian reserved file numbers in your code, you can make sure that FileIO will not use those reserved file numbers, causing a conflict with your already existing programs. The default is 1, which is fine if your software does not have any reserved file numbers.&lt;br /&gt;
&lt;br /&gt;
The allowable BR file numbers are 1-200 and 300-999.&lt;br /&gt;
&lt;br /&gt;
==== CheckIndex ====&lt;br /&gt;
&lt;br /&gt;
This function is used for Partial FileIO Implementations. If all of your software uses FileIO then all of your indexes are kept automatically up to date by the FileIO library and BR&#039;s internal file processing systems. However, if some of your programs do not use FileIO, and you use the FileIO library to add a new index file that those other programs do not know about, then its possible for the additional index file to become out of date when the master file is updated by your other programs.&lt;br /&gt;
&lt;br /&gt;
Use this setting to cause FileIO to check the DateTime stamp on all your index files when opening a new file, and automatically update any indexes that may have potentially gotten out of date from other programs.&lt;br /&gt;
&lt;br /&gt;
This option slows down the processing of the fnOpen function, particularly when running under client server over the internet. If you know that every program in your application suite uses FileIO, and that any programs that do not use FileIO still properly update all the indexes that your data file uses, then you can safely leave this setting turned off, and optimize your performance when opening several files using the fileIO system.&lt;br /&gt;
&lt;br /&gt;
==== CompressColumns ====&lt;br /&gt;
This instructs the datacrawler to use smaller widths for small columns. If CompressColumns is false, the data crawler will make the column the width of the field or the width of the caption, whichever is wider. If CompressColumns is true, it will use the width of the field, not the caption.&lt;br /&gt;
&lt;br /&gt;
==== MaxColWidth ====&lt;br /&gt;
This limits the column width to a set amount. This is applied after CompressColumns above.&lt;br /&gt;
&lt;br /&gt;
==== LogLibrary$ ====&lt;br /&gt;
If a library is specified here, then fileio looks for a BR library with the specified name, and attempts to call a library function in it called fnFileIOLog that. This function should expect six parameters, which are Logstring$, Login_Name$, Session$, Days of Date$, Time$, and CallingProgram$, if LogLayout is also nonblank.&lt;br /&gt;
&lt;br /&gt;
If you specify a LogLibrary and LogLayout is blank, then it calls your function giving it only 1 parameter.&lt;br /&gt;
&lt;br /&gt;
It will call your function &#039;&#039;&#039;&#039;&#039;instead of&#039;&#039;&#039;&#039;&#039; the normal log file. Use this to implement your own logging functions however you want.&lt;br /&gt;
&lt;br /&gt;
==== LogLayout$ ====&lt;br /&gt;
Use this setting to specify an alternate file layout for an alternate file to do the logging in. Base the file layout for this file on the logfile we supply for you in the filelay folder. It should have at least those fields, which our log routine will automatically populate, but you can add other fields if you want (though you will need to manage them yourself).&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t specify LogLayout, the default filelay\logfile will be used. This will allow you to also use the fnViewLogFile function to access it.&lt;br /&gt;
&lt;br /&gt;
==== AnimateDataCrawler ====&lt;br /&gt;
The sister library [[ScreenIO]] has a feature that allows you to use an animation of a clock in your loading screens in your own programs. If you have [[ScreenIO]] then FileIO will automatically detect it and use it to display a loading animation while the data in the data crawler loads.&lt;br /&gt;
&lt;br /&gt;
Set AnimateDataCrawler to false (0) in your fileio.ini file to bypass the animations if you do have screenio but don&#039;t want to see the animations anyway.&lt;br /&gt;
&lt;br /&gt;
==== TemplatePath$ ====&lt;br /&gt;
This setting points to the folder that contains the code templates used by the Generate Code button on the main page of the Data Crawler.&lt;br /&gt;
&lt;br /&gt;
==== IgnoreLayouts$ ====&lt;br /&gt;
This is a comma delimited list of all layouts that you wish to suppress from appearing on the main page of the data crawler. You can still access these layouts with your code, but they won&#039;t be listed in the data crawler for you to access.&lt;br /&gt;
&lt;br /&gt;
Whatever you&#039;re using for a log layout, is automatically added to this list.&lt;br /&gt;
==== CloseFileSimple ====&lt;br /&gt;
The fnCloseFile function closes all the individual handles to a data file that was opened for output using multiple keys.&lt;br /&gt;
&lt;br /&gt;
For BR 4.18 and higher, we support a better algorithm for detecting which files are matches for a given opened file number.&lt;br /&gt;
&lt;br /&gt;
Set CloseFileSimple to true (1) to force it to check the old way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== FileIO Add-on Packages ==&lt;br /&gt;
&lt;br /&gt;
Many FileIO Add-on packages are currently in the works.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Library ===&lt;br /&gt;
&lt;br /&gt;
The [[ScreenIO Library]] is a sister library to the FileIO library. The ScreenIO library requires the FileIO library in order to run.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO library is a complete Rapid Application Design tool that enables you to implement custom screen functions anywhere in your exiting programs.&lt;br /&gt;
&lt;br /&gt;
If you call the ScreenIO Library as a function library, you call a function called fnFM and tell it which screen you wish to use. The ScreenIO library loads your user interface, loads your data files, and preforms all the file maintenance operations you have designed into your screens.&lt;br /&gt;
&lt;br /&gt;
You can find out the latest information about the ScreenIO library in the ScreenIO page.&lt;br /&gt;
&lt;br /&gt;
=== Audit BR ===&lt;br /&gt;
&lt;br /&gt;
The [[AuditBR|Audit BR]] developer tool makes a backup copy of your file layouts. Then you run some code you&#039;re trying to test, and finally, run Audit BR again, to get a report showing all the changes to any of your data files automatically.&lt;br /&gt;
&lt;br /&gt;
== What’s New (also described above) ==&lt;br /&gt;
=== 2018 ===&lt;br /&gt;
*Support for dates in any storage formats on disk (v2.48)&lt;br /&gt;
&lt;br /&gt;
=== 2015 ===&lt;br /&gt;
*Added Rec to display for fnShowData&lt;br /&gt;
*Added FormStatement$ for debugging of form statements inside fileio&lt;br /&gt;
*Added mat BadRead$ for debugging of 726 errors when making new layouts&lt;br /&gt;
*Fixed a bug causing crash when logging things from long program folders&lt;br /&gt;
*fnClientEnv$ - reads a Windows Environment variable on the client using the command shell&lt;br /&gt;
*fnAskCombo$ - added an optional parameter to set default selection.&lt;br /&gt;
&lt;br /&gt;
=== 2010 - 2014 ===&lt;br /&gt;
*FileIO now caches your file layouts in memory to make it much faster then before when opening the same data file in multiple programs.&lt;br /&gt;
*Generate Layout Wizard&lt;br /&gt;
*fnShowData&lt;br /&gt;
*Improved Logging&lt;br /&gt;
*fnViewLogFile&lt;br /&gt;
*Import/Export&lt;br /&gt;
*Import/Export by Function&lt;br /&gt;
*Many other speed increases&lt;br /&gt;
*if ScreenIO is present, Datacrawler uses the animation routines&lt;br /&gt;
*fnBuildProcFile &amp;amp; fnRunProcFile&lt;br /&gt;
*fnGenerateLayout &amp;amp; fnWriteLayout&lt;br /&gt;
*fnReadForm$&lt;br /&gt;
*fnReadFormAndSubs&lt;br /&gt;
*fnGetFileDateTime$&lt;br /&gt;
*fnReadLayoutPath$&lt;br /&gt;
*fnSortKeys&lt;br /&gt;
*fnSetLogChanges&lt;br /&gt;
*fnLogChanges&lt;br /&gt;
*fnLogArray&lt;br /&gt;
*fnReadScreenSize&lt;br /&gt;
*fnEmpty&lt;br /&gt;
*fnEmptyS&lt;br /&gt;
*Many other useful functions that were added to the documentation at earlier dates.&lt;br /&gt;
&lt;br /&gt;
=== Spring 2009 ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;New Functions:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The FileIO Library has been updated in Spring 2009 to provide several new functions:&lt;br /&gt;
&lt;br /&gt;
*fnReadRecordWhere&lt;br /&gt;
*fnKey$&lt;br /&gt;
*fnBuildKey$&lt;br /&gt;
*fnReadUnopenedDescription$&lt;br /&gt;
*fnUpdateFile&lt;br /&gt;
*fnDisplayLength&lt;br /&gt;
*fnLength&lt;br /&gt;
*fnReadLayoutHeader&lt;br /&gt;
*fnReadEntireLayout&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Speed Increases:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Thanks to the BR [[Profiler]], we have increased the speed of FileIO fnOpen function by ten times when running over a LAN and by 100 times when running over the internet using Client Server.&lt;br /&gt;
&lt;br /&gt;
In order to get the new Speed Upgrades, you will need to make sure that you use the latest copy of the [[#fnOpen_Function|fnOpen]] function in each one of your programs that use FileIO.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Network FileIO:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
This version of FileIO has been optimized to work better in network situations.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;FnSettings: &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
There are more configuration options in the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] routine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Automatic Update Speed Fix:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The automatic update proceedure has been made to run more then 100 times faster then before according to our benchmarking tests.&lt;br /&gt;
&lt;br /&gt;
=== Fall 2008 ===&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;DataCrawler Grid:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
By popular request we added a read/write version to the data crawler. This version works exactly the same as the datacrawler did before but it displays all the contents of your data files in a grid instead of a listview. &lt;br /&gt;
&lt;br /&gt;
When you run the fileIO library as a program, it launches a tool known as the [[#DataCrawler|DataCrawler]]. The DataCrawler shows a listview displaying all your layout files in it. If you select one, it builds another listview with all the data in your selected data file.&lt;br /&gt;
&lt;br /&gt;
If you are looking at the first list of all your file layouts, and you press F5, a grid will be build displaying all the data in your data files. You can change any of the records you like, and when you&#039;re done, your changes will be saved to the data file. Additionally, you can Add or Delete records using the buttons at the bottom. Any changes you make are not written to the disk until you click the &amp;quot;Save&amp;quot; button. If you press ESC (Cancel) the grid is closed and all changes you made sinse the last save are lost.&lt;br /&gt;
&lt;br /&gt;
This tool is for programmers only. Do not give your end users access to the DataCrawler.&lt;br /&gt;
&lt;br /&gt;
Use the DataCrawler at your own risk. Gabriel Bakker and Sage AX are not responsible for any harm that comes to your data files through the use of this or any other tools we offer.&lt;br /&gt;
&lt;br /&gt;
The DataCrawler is not designed to be used to maintain your data files. It can be used carefully to correct small things in your data files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Support for Nonstandard Paths:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Many BR Vendors keep different versions of the same data files in different locations. For example, sometimes a BR vendor will use a different Data folder to represent data for different Warehouses, or Customers. In cases like this it is necessary for your programs to specify the path to your data files. They may do so by specifying the optional &amp;quot;PATH&amp;quot; parameter to your data files. See the section [[#fnOpenFile]] for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Support for Nonstandard Layout Files Path:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Old versions of the fileIO library required you to place all your file layouts in a subfolder of your program directory called &amp;quot;filelay&amp;quot;. We have now changed the Fileio library to allow you to place your file layouts any place you want. The only requirement is that they are all together in one folder by themselves.&lt;br /&gt;
&lt;br /&gt;
If you use a nonstandard path in the fileIO library, it is necessary to make a change to the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] code in your copy of fileio.br.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Prompt on Create:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The FileIO library automatically creates any data files that it can&#039;t find. This was done to make it easier to deploy your finished programs - if you had any empty data files you could omit them from the packages and they would be created when they were needed, on the fly.&lt;br /&gt;
&lt;br /&gt;
The current version of the FileIO library contains the same ability. However, it prompts you before creating any data files. This helps to avoid bugs that happen from incorrectly specifying the path to your data files.&lt;br /&gt;
&lt;br /&gt;
However, if you do intend for your data files to be autocreated, then you probably don&#039;t want your end users to modify them. Therefore, you can use the PromptOnCreate setting in the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] code to specify. If this value is set to true, then the fileIO library will prompt you whenever it attempts to Autocreate a data file. If it is set to false, then the fileIO library will create the data files without prompting you, like it always did before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;fnSettings:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The newest version of the FileIO library supports some features that require you to specify Global Settings values. These are done by modifying the contents of the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] routine at the beginning of the fileIO library.&lt;br /&gt;
&lt;br /&gt;
=== Fall 2006 ===&lt;br /&gt;
Many improvements have been made in the FileIO library over the summer. This section is intended to acquaint you with the highlights of those changes. Most of these improvements were built from ideas generated during the discussion at the April conference.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Intermixed String and Numeric Specs:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The File Library has been expanded to allow the reading of data files that contain mixed string and numeric specs. This is to aid those of you who are planning on implementing the FileIO Library on existing data files which may not be organized with strings first and numbers second.&lt;br /&gt;
&lt;br /&gt;
The central idea of the FileIO Library is based upon the reading of your data files into a String and Numeric array. This will enable you to refer to the fields in your file by using a named subscript, saying F$(FM_NAME) to refer, for example, to the farm file’s name field. The advantage to this is that when you change the file layout, all your existing programs will not have to be modified, because they will only be looking at F$(FM_NAME). If the name field changes from the third string field to the fourth, the value of FM_NAME will also change, and you won’t have to worry about updating your data files.&lt;br /&gt;
&lt;br /&gt;
However, in order to support the reading of a data file with intermixed string and numeric specs, the generated form statement will actually calculate the position of any fields that are not in order, so that the file read statement will still return all string fields first (into your string array) and the numeric fields second (into your numeric array). You do not need to worry about this; the library does it for you. All you have to do is read your file and use the data values.&lt;br /&gt;
&lt;br /&gt;
The only thing that is required is making sure that all your string subscript names end with a “$”. This will tell the library that they are strings. Thank you, George, for this suggestion.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Versioning / Automatic Updates:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The file layouts have been expanded to contain a version number. This version number will be used to determine when a file needs to be updated. The version number is the third parameter in the file layout.&lt;br /&gt;
&lt;br /&gt;
Any time you wish to change your file layouts, simply increment this version number. Each time the library attempts to open a data file, the file’s version is checked and compared with the version in the file layout. If the file layout has been changed (if the version in the file layout is greater then the version in the file) then the file will be updated to the latest version. Depending on the file size this may take a couple of moments. A simple progress bar will be displayed on screen while this is happening. The progress bar will be displayed in its own window, so it should not affect anything your programs may have had on screen.&lt;br /&gt;
&lt;br /&gt;
The library uses the following procedure for updating a file. First, the file is copied to a backup file (prefixed by the letter ‘o’ for old). So color.dat would become ocolor.dat, and color.key would become ocolor.key. Then the new file is created and marked with the proper version number. (color.dat, color.key). The old file is opened in read-only mode, and the new file is opened for OutIn. The update routine actually reads through the old file layout, and one record at a time creates a new record, using the new file layout, with the same data, saving it to the new data file.&lt;br /&gt;
&lt;br /&gt;
When it is done upgrading, the progress bar window is closed, and the file is reopened in the fashion you described in your call to fnOpen, and flow returns to your program as though nothing unusual has happened.&lt;br /&gt;
&lt;br /&gt;
If an error occurs during processing, the routine will do what it can to roll your data files back to the previous version, but please make frequent backups of your data files anyway, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Error Checking – If there is a mistake in the file layout:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The routine attempts to discover the cause of the error in the case that one is encountered due to a missing file, a file sharing violation, or an invalid or corrupt file layout. If this should happen, the program is paused, and a text message is printed out explaining the most likely source for the error, including what part of the file layout, if any, may have caused the error.&lt;br /&gt;
&lt;br /&gt;
You may then examine the printed text, and the contents of the BR system variables ERR and LINE to determine the problem. If you type “GO”, the next line will be execute “system”, ending your program.&lt;br /&gt;
&lt;br /&gt;
If the file was in the middle of an upgrade when the error happened, it will be automatically rolled back to the previous version, so that when you fix the problem and try to run your program again, the file will again attempt to update from the beginning, and you won’t have to worry about corrupted data.&lt;br /&gt;
&lt;br /&gt;
However, please backup your data before upgrading your data files anyway, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Implementation of Keys / Creation of New Data Files:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The library has been expanded to automatically create all new data files, and to automatically update any existing files. This means that in the file layout header, two new fields that were previously ignored are no longer ignored. The RECL value that you specify in your file layout will be used, along with the description/definition of your keys file. When you open a new file (or update an existing one), the library will calculate the proper kps and kln by evaluating the key description. This key description must match up with subscript values from the data elements in your file, and more then one may be specified, but they must be separated with slashes (/). If I wanted my Farm File to be keyed based on CODE and NAME, the proper key description would be:&lt;br /&gt;
&lt;br /&gt;
  farm.key, CODE/NAME&lt;br /&gt;
&lt;br /&gt;
The library will then look up the position and length on disk of the CODE and NAME fields and put them together to create the proper keys during an update or creation of a new file. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;DataCrawler:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
Perhaps the most exciting new addition to the library is the addition of a programming tool I like to call a DataCrawler. If you run the FileIO Library directly as a program, instead of using it as a library, it will function as a DataCrawler. The DataCrawler requires a New Gui version of BR, as it requires a ListView to be able to properly and easily display the data in your files.&lt;br /&gt;
&lt;br /&gt;
If you run it in an older version of BR you will get a message, telling you to run it in a newer copy. If you run it in a New Gui version of BR with CONFIG GUI OFF, then GUI will be turned temporarily on for the use of the DataCrawler and then turned off again when you are finished. If you run it in a New Gui version of BR with GUI ON, it will just run normally.&lt;br /&gt;
&lt;br /&gt;
When you run the DataCrawler, first you will see a ListView displaying every file layout it can find in the filelay folder. If you select a file, the DataCrawler will open a large ListView with as many columns as there are fields in the file. The Column Headings will come from the element descriptions in your data files, and the column widths will come from the displayed width of the fields. There will be a row for every record in your data file, and you can resize the column widths, and scroll around the data file to view the raw data of your BR data files on disk.&lt;br /&gt;
&lt;br /&gt;
If you are dealing with a particularly enormous data file (50,000+ records) it can take a moment to populate the ListView with the data in your data file. You may hit ESC to stop loading if you like, and view only the already loaded records.&lt;br /&gt;
&lt;br /&gt;
If you would like to look up a particular record (based only upon the primary key for the data file), you may press F4. This will give you a window which asks you to input the key or partial key. When you press enter, the file will be reloaded, starting at the key you specified and continuing on to the end of the file, or until you press ESC. The records you are looking for should appear at the top of the ListView.&lt;br /&gt;
&lt;br /&gt;
To reset the ListView and look at the contents of the entire file again, simply press F4, and enter a blank (“”) key.&lt;br /&gt;
&lt;br /&gt;
Finally, as with any ListView, you may resort your data by clicking on any of the column headings. Then you can use the slider bar at the right to scroll down to the record you desire.&lt;br /&gt;
&lt;br /&gt;
This is a programming tool and is not designed to be used by an end user. This tool will open your file in read-only mode. It will not allow you to modify the data; I leave that as an exercise for the reader. However, it will update any datafiles you view to the latest version (if they need to be updated) when it opens them, just as any other program that uses the library will do.&lt;br /&gt;
&lt;br /&gt;
== Appendix (Examples)==&lt;br /&gt;
&lt;br /&gt;
=== Example.br ===&lt;br /&gt;
  00010    ! example.br - This program is an example of for the data reading simplification&lt;br /&gt;
  00020    ! Copyright April 2006 by Gabriel Bakker&lt;br /&gt;
  00030    ! Distributed open source as a Christmas gift to brag members&lt;br /&gt;
  00040    !&lt;br /&gt;
  00100    execute &amp;quot;config gui off&amp;quot;&lt;br /&gt;
  01020    DIM form$(1)*255&lt;br /&gt;
  01030    DIM color$(1)*255,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*255,colorcat(1)&lt;br /&gt;
  02020    library &amp;quot;fileio&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
  04000 !&lt;br /&gt;
  04010 Openfiles: ! Open your files here&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
  06000    ! gosub WriteFiles ! If you want to test this line, make sure to drop flag from 4030&lt;br /&gt;
  07000 !&lt;br /&gt;
  07010 MainBit: ! This&#039;un here&#039;s tha Main Bit&lt;br /&gt;
  07030    RESTORE #ColorFile:&lt;br /&gt;
  07100    ReadNextcolor: ! Read next record&lt;br /&gt;
  07120       read #ColorFile, using form$(ColorFile) : mat Color$, mat Color eof EndReadColor&lt;br /&gt;
  07180       PRINT Color$(co_name)&amp;amp;&amp;quot; (&amp;quot;&amp;amp;Color$(co_html)&amp;amp;&amp;quot;) is a member of the &#039;&amp;quot;;&lt;br /&gt;
  07190       PRINT trim$(fnReadDescription$(ColorcatFile,cc_Name,Color$(co_category),mat Colorcat$,mat Colorcat,mat form$))&amp;amp;&amp;quot;&#039; category.&amp;quot;&lt;br /&gt;
  07290       goto ReadNextColor&lt;br /&gt;
  07300    EndReadcolor: ! Finished with Color File&lt;br /&gt;
  08000    STOP&lt;br /&gt;
  25000 !&lt;br /&gt;
  25010 WriteFiles: ! Uncalled routine to demonstrate writing files&lt;br /&gt;
  25105       let color$(co_code)=&amp;quot;GD&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Gold&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;FFD700&amp;quot;&lt;br /&gt;
  25110       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25115       let color$(co_code)=&amp;quot;LV&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Lavender&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;BL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;E6E6FA&amp;quot;&lt;br /&gt;
  25120       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25125       let color$(co_Code)=&amp;quot;OR&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Orange&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;FFA500&amp;quot;&lt;br /&gt;
  25130       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25205       let colorcat$(cc_Code)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_Name)=&amp;quot;Yellows&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_html)=&amp;quot;FFFF00&amp;quot;&lt;br /&gt;
  25210       write #colorcatfile, using form$(colorcatfile): mat colorcat$,mat colorcat&lt;br /&gt;
  25215       let colorcat$(cc_Code)=&amp;quot;BL&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_Name)=&amp;quot;Blues&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_html)=&amp;quot;0000FF&amp;quot;&lt;br /&gt;
  25220       write #colorcatfile, using form$(colorcatfile): mat colorcat$,mat colorcat&lt;br /&gt;
  25300    return&lt;br /&gt;
  40000 !&lt;br /&gt;
  40010 Open: ! ***** Function to call library openfile and proc subs&lt;br /&gt;
  40020    def fnOpen(FILENAME$, MAT F$, MAT F, MAT FORM$;INPUTONLY,KEYNUM,___,INDEX)&lt;br /&gt;
  40025       dim _FileIOSubs$(1)*50&lt;br /&gt;
  40030       let fnopen=fnopenfile(FILENAME$, MAT F$, MAT F, MAT FORM$,INPUTONLY,KEYNUM,MAT _FileIOSubs$)&lt;br /&gt;
  40040       for Index=1 to udim(mat _FileIOSubs$) : execute (_FileIOSubs$(Index)) : next Index&lt;br /&gt;
  40090    fnend&lt;br /&gt;
  50000 !&lt;br /&gt;
  60000 Ignore: Continue&lt;br /&gt;
  &lt;br /&gt;
  Color File Layout&lt;br /&gt;
  color.dat, CO_, 1&lt;br /&gt;
  color.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Color Code,                  C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  CATEGORY$,      General Category of Color,   C    6&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
&lt;br /&gt;
  ColorCat File Layout&lt;br /&gt;
  colorcat.dat, CC_, 0&lt;br /&gt;
  colorcat.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Category Code,               C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
  &lt;br /&gt;
Example Layout showing multiple keys (price)&lt;br /&gt;
  price.dat, PR_, 0&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  X,              Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=File:Dates0.png&amp;diff=10966</id>
		<title>File:Dates0.png</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=File:Dates0.png&amp;diff=10966"/>
		<updated>2018-09-18T16:10:31Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=FileIO_Library&amp;diff=10965</id>
		<title>FileIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=FileIO_Library&amp;diff=10965"/>
		<updated>2018-09-18T16:09:50Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* File Layouts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;FileIO&#039;&#039;&#039; Library began as a project to find a way to reduce the headache associated with making changes to data files. In my experiences working for [[BRC]], I had to make a change to the commun file, a data file that stores information about communication with EDI VANs. I added some new fields, and removed a couple of old fields, and then I began searching through the BRC program suite to find and modify each program that referenced this data file in order to update it with the proper new form statement. This task quickly became daunting as I noticed that out of BRC’s program suite of over 600 programs, more than one third of them referenced the commun file. With 223 programs to modify, the task was given up as hopeless and tabled indefinitely.&lt;br /&gt;
&lt;br /&gt;
I am happy to announce that we have solved this problem. When I have to make a change to a data file layout for my customers today, I can complete the task in under 1 minute, and not a single program needs to be changed in order to continue working with the new file layout. In fact, I don’t even have to update my customer’s data files, as the FileIO library takes care of this for me as well.&lt;br /&gt;
&lt;br /&gt;
The trick is to define your file layouts in an ASCII text file layout file that I will tell you about in a minute. The FileIO Library will actually parse through your file layouts, and it will instruct your programs how to read the data file, so that you don’t have to. It will also automatically detect when you make changes to the file layout, and it will update your customer’s data files on the fly to make sure they have the latest version. Finally, it even contains a DataCrawler that you can use to examine the contents of any of your BR data files in a raw format.&lt;br /&gt;
&lt;br /&gt;
For more information about the FileIO Library visit the [http://www.sageax.com/products/fileio-library/ Sage AX Website]&lt;br /&gt;
&lt;br /&gt;
To download the latest copy of FileIO, click [http://www.sageax.com/downloads/FileIO.zip here.]&lt;br /&gt;
&lt;br /&gt;
== Method of Operation ==&lt;br /&gt;
The file IO library parses a formatted text file layout and uses this information to structure the opening and initializing of the reading of a file “object”. The word object here is used to refer to all the data in a given record layout in one of your files. This library is easy to use, and provided you follow some simple standards, it will simplify your life immensely.&lt;br /&gt;
&lt;br /&gt;
You will need to define one array for all forms and add a snippet of code (given below) to the program for interfacing with with the library. For each file you will need to define a couple of arrays and use the library to open them. From that point on access to data is simple and direct. &lt;br /&gt;
&lt;br /&gt;
=== File Object Arrays ===&lt;br /&gt;
&lt;br /&gt;
First, in your program you must create two arrays to store the file information. If we are dealing with the Color File these would be MAT COLOR$ and MAT COLOR. One will store all the string information about a color, and the other will store all the numeric data. Our working example will involve two files: a Color File and a Color Category File. You should dimension these to:&lt;br /&gt;
&lt;br /&gt;
  01030    DIM color$(1)*1000,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*1000,colorcat(1)&lt;br /&gt;
&lt;br /&gt;
We&#039;re dimensioning the string arrays to 1000. This is the length of one field in the color file. It needs to be at least as big as the largest string field in the data file.&lt;br /&gt;
&lt;br /&gt;
However, it is recommended to make sure the length is long enough to handle any field you might eventually add to the file at any point in the future. BR supports multi-line textboxes, so I sometimes add long memo fields to my data files that might be 400 or 800 or even 1000 characters long, therefore 1000 is the length I use now in all my new development.&lt;br /&gt;
&lt;br /&gt;
But anything will work as long as its long enough to handle the largest data field in your file.&lt;br /&gt;
&lt;br /&gt;
=== Forms Array ===&lt;br /&gt;
&lt;br /&gt;
You will also need a variable to store the form statement associated with reading the files. This form statement will be dynamically generated whenever a new file is opened. It will say: &lt;br /&gt;
&lt;br /&gt;
  01020    DIM form$(1)*255&lt;br /&gt;
&lt;br /&gt;
This form statement will be compiled by the FileIO open statement and BR limits all form statements to 255 bytes compiled anyway, so 255 is enough for the Forms$ array.&lt;br /&gt;
&lt;br /&gt;
=== Library Linkage ===&lt;br /&gt;
&lt;br /&gt;
You will also need the library statement:&lt;br /&gt;
&lt;br /&gt;
  02020 library &amp;quot;fileio.br&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
&lt;br /&gt;
=== fnOpen Function ===&lt;br /&gt;
&lt;br /&gt;
Now, add a snippet of code to interface with the library.&lt;br /&gt;
&lt;br /&gt;
Because BR libraries do not share variables with the programs they are called from, we will need to execute a proc file whenever we open a file to set the names of all our variables after we return. Add the following snippet of code into your program. It will create an FnOpen function that calls the library version and runs the proc file. The $$$ at the end of the procfile name tells the procfile to self-destruct after execution. Since this procfile is used simply to return variable information back from the library to the main program, we don’t need it sitting around collecting dust.&lt;br /&gt;
&lt;br /&gt;
  99010 OPEN: ! ***** Function To Call Library Openfile And Proc Subs&lt;br /&gt;
  99020    def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths,Supress_Prompt,Ignore_Errors,Suppress_Log,___,Index)&lt;br /&gt;
  99030       dim _FileIOSubs$(1)*800, _Loadedsubs$(1)*80&lt;br /&gt;
  99040       let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$, Supress_Prompt,Ignore_Errors,Program$,Suppress_Log)&lt;br /&gt;
  99050       if Srch(_Loadedsubs$,Uprc$(Filename$))&amp;lt;=0 then : mat _Loadedsubs$(Udim(_Loadedsubs$)+1) : let _Loadedsubs$(Udim(_Loadedsubs$))=Uprc$(Filename$) : for Index=1 to Udim(Mat _Fileiosubs$) : execute (_Fileiosubs$(Index)) : next Index&lt;br /&gt;
  99060    fnend&lt;br /&gt;
&lt;br /&gt;
Or, for those with [[Lexi]]:&lt;br /&gt;
  OPEN: ! ***** Function To Call Library Openfile And Proc Subs&lt;br /&gt;
     def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths,Supress_Prompt,Ignore_Errors,Suppress_Log,___,Index)&lt;br /&gt;
        dim _FileIOSubs$(1)*800, _Loadedsubs$(1)*80&lt;br /&gt;
        let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$, Supress_Prompt,Ignore_Errors,Program$,Suppress_Log)&lt;br /&gt;
        if Srch(_Loadedsubs$,Uprc$(Filename$))&amp;lt;=0 then : mat _Loadedsubs$(Udim(_Loadedsubs$)+1) : let _Loadedsubs$(Udim(_Loadedsubs$))=Uprc$(Filename$) : for Index=1 to Udim(Mat _Fileiosubs$) : execute (_Fileiosubs$(Index)) : next Index&lt;br /&gt;
     fnend&lt;br /&gt;
&lt;br /&gt;
=== Using FileIO in Your Programs ===&lt;br /&gt;
Now you are ready to process files. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;You simply open the files by saying:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;read each file as follows:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  30120    read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore  &lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;and access the data:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  30180    LET ColorCode$=color$(co_Code) !:&lt;br /&gt;
           LET ColorName$=color$(co_Name)&lt;br /&gt;
&lt;br /&gt;
=== How it Works ===&lt;br /&gt;
These statements tell the File Library to look in the filelay folder to find the file layout for the Color File, and read it to find out what the Color File looks like. Then Open the Color File, and set MAT COLOR$ and MAT COLOR to the correct number of elements to hold an entire color record. Finally, it will define several variables that we can use as pointers into (subscripts) these arrays to access the data we after reading it, and it will place the file handle into a variable called colorfile.&lt;br /&gt;
&lt;br /&gt;
The second open above will do the same thing to the color category file, except the 1 parameter tells the function to open readonly. The subscripts array will be executed, creating the subscripts in memory, and the pointers (subscripts) will be set in the calling program. So, if I had a file layout such as the following:&lt;br /&gt;
&lt;br /&gt;
  color.dat, CO_, 1&lt;br /&gt;
  color.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Color Code,                  C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  CATEGORY$,      General Category of Color,   C    6&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
&lt;br /&gt;
Then the functions would do the same thing as the following individual lines of code (assuming the next available file handle was 5):&lt;br /&gt;
&lt;br /&gt;
  DIM FORM$(5)*255&lt;br /&gt;
  DIM COLOR$(9)*1023, COLOR(1)&lt;br /&gt;
  OPEN #5: “Name=color.dat, kfname=color.key”,internal,outin,keyed&lt;br /&gt;
  LET FORM$(5)=”form C 6,V 30,V 6,C 6”&lt;br /&gt;
  LET FORM$(5)=CFORM$(FORM$(5))&lt;br /&gt;
  LET COLORFILE=5&lt;br /&gt;
  CO_CODE=1&lt;br /&gt;
  CO_NAME=2&lt;br /&gt;
  CO_CATEGORY=3&lt;br /&gt;
  CO_HTML=4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The data is used by referencing the file array, with the subscript name, so the color’s description becomes color$(co_Name).&lt;br /&gt;
&lt;br /&gt;
In the old days, if we wanted to change the file layout of our file, all of the programs that used that file would have to be changed one at a time to use the new file layout. Also, if the order of the fields changed, then all the programs would have to also be changed to use the new fields.&lt;br /&gt;
&lt;br /&gt;
But now, using this function, we can change the file layout all we want. If we later want to insert a field into the file layout before color name, I won’t have to look at this program again; this program will just work fine, because the library maps the subscripts to the actual fields.&lt;br /&gt;
&lt;br /&gt;
Also, the code is easier to read and maintain.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
The whole thing looks like this:&lt;br /&gt;
&lt;br /&gt;
  01025    ! Dimension the Arrays&lt;br /&gt;
  01030    DIM color$(1)*1023,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*1023,colorcat(1)&lt;br /&gt;
  01050    DIM form$(1)*255&lt;br /&gt;
  02000 !&lt;br /&gt;
  02020 library &amp;quot;fileio.br&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$) ! Open the file&lt;br /&gt;
  05000 ! &lt;br /&gt;
  30120    read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore ! Read the file&lt;br /&gt;
  30180    LET ColorCode$=color$(co_Code) !:&lt;br /&gt;
           LET ColorName$=color$(co_Name) ! Use the data by referincing it in the file arrays&lt;br /&gt;
  80000 !&lt;br /&gt;
  90000 ! Every program using fileio needs the following code&lt;br /&gt;
  99010  OPEN: ! ***** Function To Call Library Openfile And Generate Subs&lt;br /&gt;
  99020     def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths)&lt;br /&gt;
  99030        dim _FileIOSubs$(1)*800&lt;br /&gt;
  99040        let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$)&lt;br /&gt;
  99050        for Index=1 to udim(mat _FileIOSubs$) : execute (_FileIOSubs$(Index)) : next Index&lt;br /&gt;
  99060     fnend&lt;br /&gt;
&lt;br /&gt;
== File Layouts ==&lt;br /&gt;
Now lets inspect the anatomy of a properly formatted file layout. These should be placed in a subdirectory called filelay.&lt;br /&gt;
&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  X,              Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
&lt;br /&gt;
The first line contains the name of the Farm File, a unique string to prefix all of your subscript pointers, and the file version number. The subscript value is to ensure that the program knows the difference between the Farm File’s Farm Code, and the Route File’s Route Code. (One will be RT_CODE and the other is FM_CODE).  These are separated by a comma. Spacing does not matter, so adjust your spacing so that it looks nice.&lt;br /&gt;
&lt;br /&gt;
The Version number is used to determine when the data has changed, and an update needs to be made to your data file. Your file layouts should all start at version 0, and each time you want to make a change, you may increment this value by 1.&lt;br /&gt;
&lt;br /&gt;
Each time you open a file with the FILEIO library, it reads the file version number of the file on disk (using the BR version() function), and then it compares it to the version number in your file layout. If your file layout has a higher version number then your existing data file, then the library opens the backup of the file layout for the version of the data file that exists on disk. It makes a backup copy of the existing data file, and creates a new file with the proper version number. Then it reads your records one at a time, and copies all the data from the old file into the new file one field at a time. If a field is dropped from the file layout, that data gets lost. If fields are rearranged, the data is copied and saved in the new file in the new positions. If a new field is added, it starts out blank (or 0).&lt;br /&gt;
&lt;br /&gt;
If you look in the filelay folder, you will notice a version folder. This contains several files ending with a number. For example you may see a color.0, and a color.1 file.&lt;br /&gt;
&lt;br /&gt;
If you run the fnopen function and it can not find your data file (usually because this is a new file and it hasn’t been created yet), &#039;&#039;the library will automatically create your file,&#039;&#039; based on the information you give in the first part of the file layout.&lt;br /&gt;
&lt;br /&gt;
Also, whenever you make changes to your file layout, the function library will automatically update the data files on disk for you. It does this by renaming the old file, creating a new one with the new version number, and then copying the data from the old one to the new one a record at a time.&lt;br /&gt;
&lt;br /&gt;
Any time it creates a file, or updates the file on disk, it creates a backup of the file &#039;&#039;layout&#039;&#039;. The first time you run a program that tries to read your new data file, it will create the data file for you and make a backup of the layout, and if the number in your file layout is 0, then it will create, for example, a filelay\version\price.0 file, a backup of your file layout that the library uses to figure out what has changed the next time you try to update the file.&lt;br /&gt;
&lt;br /&gt;
If you wish to make any changes to this data file, first you increment the version number, (in this case make the 0 into a 1). Then change the file layout all you want. You may rearrange fields, add new fields, add or remove keys, or change the record length.&lt;br /&gt;
&lt;br /&gt;
The only step necessary for having your data files updated is to increment the version number every time you make a change to the file layout.&lt;br /&gt;
&lt;br /&gt;
You may make any changes you like to the file layouts, but do not change the names of your existing subscripts. If you change the subscript name, not only will all the programs that reference that subscript be broken, but additionally, the routine will not understand that you are changing the name. It will think you are dropping the old field and adding a new field and any data stored in this location will be lost when the file is updated.&lt;br /&gt;
&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
&lt;br /&gt;
The second line contains the name of the first key, and a definition telling what the key is based on. These are separated by a comma. The key definition is made up of each of the subscript names in this file that form the keyfields for the file. When the library is called to open a file, if the file does not exist, or if it needs to be updated, a new one will be created. The function will read these subscript names that form your key definitions, and it will calculate the proper key position (KPS=) and length (KLN=) values. Then the create routine will use this information with the Index command to create the new key files.&lt;br /&gt;
&lt;br /&gt;
  price.key, ITEM&lt;br /&gt;
  price.ky2, FARM&lt;br /&gt;
  price.ky3, ITEM/FARM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
&lt;br /&gt;
Notice that the third key is based on three different fields. These are separated by a “/”. It is important that you use a “/” to separate your keys when you are building a key out of more then one field, because the function uses this “/” to help it make the proper BR syntax for defining complex key fields.&lt;br /&gt;
&lt;br /&gt;
The file can have as many keys as you want. The function will keep parsing key file names until it reaches the next part of the layout. It opens any OutIn files with all keys so that any changes you may make to the data stored on disk will be properly reflected in all the key files.&lt;br /&gt;
&lt;br /&gt;
The optional RECL= Parameter is read and used whenever a new file is created or an old one is updated. If it is not specified, the record length is calculated from the fields in the layout.&lt;br /&gt;
&lt;br /&gt;
  ===================================================&lt;br /&gt;
&lt;br /&gt;
The next line in the file is skipped by the parsing routine, and its purpose is to make the file layouts more readable to a programmer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
&lt;br /&gt;
Following the file and key structure, the fields are defined. There are three parameters on each field definition line, and you make one line for each field in your file layout. The first parameter is the subscript name that you will use in your program to refer to this data element. Place a $ at the end of the subscript name for all string elements. Don’t place anything at the end of the subscript name for numeric elements. Note that each of these names will be prefixed by the second parameter of the very first line of this layout. &lt;br /&gt;
&lt;br /&gt;
The second parameter is the description. This description is for the benefit of the programmer, so when the programmer is reading the file layouts, (s)he can tell which field does what. The spaces are ignored, so you may include as many spaces as you wish to make the layout look good. It does seem like good general guidelines would be to limit your layout lines to 255 characters and your descriptions to 80. &lt;br /&gt;
&lt;br /&gt;
The description is also used by the built in DataCrawler, a program that reads any of your data files and displays the entire contents in raw form in a listview. The Descriptions become the headings for each column in the listview. &lt;br /&gt;
&lt;br /&gt;
Those descriptions are also used for the default captions for your fields if you use ScreenIO, a library for building GUI programs that itself builds off of fileio.&lt;br /&gt;
&lt;br /&gt;
The third parameter is the form statement, which is pretty straightforward. Any items with a form statement of type “X” will be ignored, except that the length will still be used to calculate the position on disk of all remaining fields in the record. The library will take X fields into consideration when building the form statement, but not at any other time.&lt;br /&gt;
&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
Comment line text must begin with an exclamation point, but it may be indented. Comment lines may appear anywhere (vertically) and are ignored. &amp;lt;br&amp;gt;&lt;br /&gt;
Blank lines are ignored as well.&lt;br /&gt;
&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
After the last field definition, an &#039;&#039;optional&#039;&#039; #eof# line may be specified, in which case any lines after that will be ignored. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  DUMMY,          Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
&lt;br /&gt;
And that’s all there is to it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tips ===&lt;br /&gt;
&lt;br /&gt;
When you&#039;re making new layouts, a missing comma can cause FileIO to parse the layout wrong and give you errors. Here are a couple tips to help ensure your layouts are error free before using them in your programs.&lt;br /&gt;
&lt;br /&gt;
*Use the Data Crawler to test your layout. The data crawler is the simplest way to test your new layout without writing any code. It opens it and accesses the file in a very simple and straight forward manor to help identify any errors in the layout that you might have.&lt;br /&gt;
&lt;br /&gt;
*If you have trouble with the form statement, you can&#039;t see whats in it because FileIO uses CForm$ to compile your form statement to make your programs run faster. But here&#039;s a way to tell what the original form statement was that FileIO generated when it put the strings first and numbers last in your program: Open the file in the Data Crawler. When you get an error, type &amp;quot;Print FormStatement$&amp;quot; to see the original form statement.&lt;br /&gt;
&lt;br /&gt;
This works even if your file is working fine. Any time the file is opened with the data crawler, you can press CTRL-A and then type PRINT FormStatement$ and it will print out the uncompiled form statement for the file.&lt;br /&gt;
&lt;br /&gt;
== Support for Dates ==&lt;br /&gt;
As of V2.48, file layouts support dates in any storage formats on disk. Whether you store your dates in Julian or in YMD or MDY or any other format, specify so in the 4th column of your file layouts, using the FileIO Date Keyword. ex: DATE(Julian) or DATE(YMD) or any other valid BR Date Format.&lt;br /&gt;
&lt;br /&gt;
[[File:Dates0.png]]&lt;br /&gt;
&lt;br /&gt;
When this is specified, it enables the FileIO data exploration tool (Data Crawler) to display the dates in human readable format. This works for both Viewing, and for Editing.&lt;br /&gt;
&lt;br /&gt;
The new Date functionality also supports the File Layout Upgrade facility, allowing you to change the format of your dates on disk and FileIO will handle it automatically, upgrading the field to use the new date format for you.&lt;br /&gt;
&lt;br /&gt;
It works also for Exporting your data files to CSV, and is supported automatically in the FileIO functions that do those exports. It converts the dates on export to a standard format (Default: m/d/cy) that you can specify in your FileIO.Ini File.&lt;br /&gt;
&lt;br /&gt;
This update adds two new ini file options:&lt;br /&gt;
 CODE: SELECT ALL&lt;br /&gt;
&lt;br /&gt;
 DateFormatExport$=&#039;m/d/cy&#039;  ! Format of Dates when Exporting to CSV&lt;br /&gt;
 DateFormatDisplay$=&#039;m/d/cy&#039; ! Format of Dates when displaying in Data Crawler&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can use these to specify your preferred Date format for Viewing/Editing, and your preferred Date format for Exporting.&lt;br /&gt;
&lt;br /&gt;
Remember, you can see the full list of FileIO ini file options, by looking in the source code at the top of FileIO.&lt;br /&gt;
&lt;br /&gt;
There is a new optional parameter for all layout reading functions, mat NDateSpec$ and mat SDateSpec$ which correspond with the other arrays, to let you know which fields are date fields, so that you can develop routines in your programs to automatically pack and unpack the dates.&lt;br /&gt;
&lt;br /&gt;
Important Note: Using FileIO, the reading of the data file is still done directly in your programs. So this does not change how your existing programs work. It does not unpack the dates for you in your programs. You still have to do all that.&lt;br /&gt;
&lt;br /&gt;
For this reason, upgrading to the new Date processing will not break any of your current code.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
Now that you have your file layouts defined, you have access to several powerful utilities right out of the box using Fileio. Additionally, several more utilities are available as [[#FileIO_Add-on_Packages|Add-Ons]], including our most popular development tool [[Screenio|ScreenIO]]. You can read more about them in their section below.&lt;br /&gt;
&lt;br /&gt;
But for now, lets take a look at some of the wonderful free utilities that come built into Fileio.&lt;br /&gt;
&lt;br /&gt;
Some of these utilities are accessible from your code via library functions, but the primary way you access any of them is by simply loading the FileIO Library and running it directly.&lt;br /&gt;
&lt;br /&gt;
=== DataCrawler ===&lt;br /&gt;
The data crawler is the original utility of FileIO. This utility shows you first a list of all data files allowing you to select one.&lt;br /&gt;
&lt;br /&gt;
Select a data file and press enter, and FileIO will then display a listview containing all the data in the data file. This list is sized based on the size of your main BR window (window 0) automatically to take up the full size available to it, so if you want to see more, try [[Open Window|opening window 0]] larger before running FileIO.&lt;br /&gt;
&lt;br /&gt;
At the top of the window is a filter box, and you can type anything you want in there and click &amp;quot;Refresh&amp;quot; and it will reread the data file, shortening the list to show only those records that match (case insensitive) what you have typed.&lt;br /&gt;
&lt;br /&gt;
If you have ScreenIO installed, then FileIO&#039;s data crawler will take advantage of the included Animation Engine in ScreenIO to animate a loading window while the listview is displaying. If you don&#039;t have ScreenIO then FileIO will simply load the listview.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want to wait for the entire file to load, press ESC to stop the load process.&lt;br /&gt;
&lt;br /&gt;
If the file is empty, FileIO will display a message box letting you know.&lt;br /&gt;
&lt;br /&gt;
This tool is very useful for sorting out data errors. It will allow you to look inside any data file you have a layout for and directly view the data there.&lt;br /&gt;
&lt;br /&gt;
At the bottom of the Data Crawler are several buttons. There&#039;s a Jump button that repositions the file by a key you specify and then loads the list with the data from that key on down to the end of the file.&lt;br /&gt;
&lt;br /&gt;
There is a &amp;quot;Columns&amp;quot; button which you can use to decide which columns should show up on the listview. Fewer columns means faster loading so sometimes for large files I press ESC immediately when the file first starts loading to cancel the load. Then I click &amp;quot;Columns&amp;quot; and check only the columns I want to see. Finally I press the &amp;quot;Refresh&amp;quot; button to trigger it to read the file again and this time it loads much faster then before.&lt;br /&gt;
&lt;br /&gt;
Next you&#039;ll find an Export button which starts the process for exporting a file to CSV. You can read more on that in the next section. And next to that is a Quit button.&lt;br /&gt;
&lt;br /&gt;
In this example, we loaded the file &amp;quot;Read Only&amp;quot; so it put everything in a listview. But there are times when its useful to fix data errors this way too, especially during development. So if you want to directly edit your data file, on the first page select the file you want to edit and instead of pressing &amp;quot;Enter&amp;quot; or clicking &amp;quot;View&amp;quot;, this time press &amp;quot;F5&amp;quot;. F5 is the secret Edit button that loads a data file into a grid instead.&lt;br /&gt;
&lt;br /&gt;
You can use the grid to change records, delete them or add them, and in addition to the buttons listed above, it also has an &amp;quot;Import&amp;quot; button for importing a CSV file into this data file.&lt;br /&gt;
&lt;br /&gt;
Any changes you make to the data file are not saved until you click the &amp;quot;Save&amp;quot; button (which also only appears when you&#039;re in Edit mode).&lt;br /&gt;
&lt;br /&gt;
In the 01/2015 release of FileIO, each records rec # is displayed in the listview, to aid in debugging bad data problems.&lt;br /&gt;
&lt;br /&gt;
==== Debugging Tip ====&lt;br /&gt;
Any time you&#039;re viewing a file layout in the Data Crawler, you can see the Uncompiled Form Statement by pressing CTRL-A to get to an ATTN prompt, and then entering the command:&lt;br /&gt;
&lt;br /&gt;
  print FormStatement$&lt;br /&gt;
&lt;br /&gt;
and it will print out the original form statement.&lt;br /&gt;
&lt;br /&gt;
==== Another Debugging Tip ====&lt;br /&gt;
&lt;br /&gt;
The FileIO Datacrawler ignores records that it cannot read. This is to allow for data files that have multiple record layouts in one data file. You make a custom layout for each record type and the data crawler shows just the records that match that type in the file.&lt;br /&gt;
&lt;br /&gt;
However that becomes a problem when you&#039;re making a layout to work with an existing data file. Error 726 indicates that something minor in the file layout doesn&#039;t match the data on the disk, but these errors are ignored so you might see either an empty data file, or a data file with some records missing. If that happens, you need to see the missing records in order to figure out what is wrong with your layout. &#039;&#039;&#039;&#039;&#039;It&#039;s very important that you don&#039;t try to use a file layout that isn&#039;t quite working right. Make sure your layout works and can read every record of a file that it should read before using it.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To see the records that could not be read in a file, run the data crawler on the layout, then press CTRL-A to get an ATTN prompt. From there, enter the command&lt;br /&gt;
&lt;br /&gt;
  print mat BadRead$&lt;br /&gt;
&lt;br /&gt;
and it will print all the records that were ignored because the file layout didn&#039;t match them. It prints out the raw data from the file.&lt;br /&gt;
&lt;br /&gt;
==== Function Access to use Data Crawler in your programs ====&lt;br /&gt;
You can use the data crawler in your own programs by using one of the following functions:&lt;br /&gt;
* [[#fnDataCrawler|fnDataCrawler]] - Open a Listview showing the data file&lt;br /&gt;
* [[#fnDataEdit|fnDataEdit]] - Display the data in an editable grid&lt;br /&gt;
* [[#fnShowData|fnShowData]] - This function does the same thing as the above two, but with many many more options allowing you to customize exactly what appears and exactly what they&#039;re allowed to change.&lt;br /&gt;
&lt;br /&gt;
Note: its not recommended to allow your customers to use the data crawler to access your data files directly. There&#039;s no way to specify validations or do anything complicated, so unless you&#039;re careful, there are lots of ways your customers could use this tool to do damage to your data files. It is a programmer tool only.&lt;br /&gt;
&lt;br /&gt;
If you do decide to use it for your end users, be careful how you implement it.&lt;br /&gt;
&lt;br /&gt;
=== Import/Export to CSV ===&lt;br /&gt;
&lt;br /&gt;
You can use FileIO to export your data files to CSV or import from CSV into your data file. To do this, you want to run the data crawler and select the file layout you&#039;re looking for. Then, view it (or press F5 to edit if you want to import something). Click on the Export button and it will ask you to select a file. Once that is selected it will ask a couple other simple questions, and when you&#039;ve specified the options to your satisfaction, click the Export! button. A new CSV file will be created.&lt;br /&gt;
&lt;br /&gt;
Import is even more simple. To import, you must be in Edit mode (press F5 to select the file instead of the enter key) and then simply select the Import button. It will ask you again to choose the file, and then it will ask you if it should update all files by Record Number (if record number is recorded in the CSV file) or by Key (if the file has keys) or to just Add all information to the file. Select what you want and press Import and the CSV file is added to the BR data file.&lt;br /&gt;
&lt;br /&gt;
==== Function Access to Import/Export from your programs ====&lt;br /&gt;
&lt;br /&gt;
You can use the following functions to call the Import and Export functionality from your code.&lt;br /&gt;
&lt;br /&gt;
*[[#fnCSVImport|fnCSVImport]]&lt;br /&gt;
*[[#fnCSVExport|fnCSVExport]]&lt;br /&gt;
&lt;br /&gt;
These functions are intended to give you the ability to use our functionality to write your own import and export routines for your customers, because its not a good idea to let your customers run the Data Crawler.&lt;br /&gt;
&lt;br /&gt;
=== Generate Layout Wizard ===&lt;br /&gt;
&lt;br /&gt;
There is also a Generate Layout Wizard utility in FileIO. This utility is there to help you build your file layouts. It is designed to work with a certain style of BR programming that was common in the 80s and 90s. So if your software is written in a style that opens the file directly, and reads/writes the data to a long series of individual variables, the Generate Layout Wizard is for you.&lt;br /&gt;
&lt;br /&gt;
To use it, start by running FileIO. Then, don&#039;t select a layout - instead, click on the &amp;quot;Generate Layout&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
You&#039;ll see a screen with a bunch of large text boxes, a small grid, and some buttons.&lt;br /&gt;
&lt;br /&gt;
The first thing you want to do is select the &amp;quot;Browse&amp;quot; button and then select a .wb or .br file that contains a program that reads or writes Most of the File.&lt;br /&gt;
&lt;br /&gt;
When you select one, press the Scan All button and it fileio will search the whole program looking first for all the open strings. It will take the file that is opened the most times and then search for all read statements to that file. It will look for the longest read statement and then find the Form statement associated with that Read statement, and any DIM statements for any variables used.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t like the file its chosen, click the &amp;quot;Open Scratch Pad&amp;quot; button to open the temp work file it uses into the program of your choice (I use myEdit for BRS files). Simply select all the open statements for the file you DO want to build off of, then click the Paste button to paste those open statements into the &amp;quot;Open String&amp;quot; list. After that click &amp;quot;Clear All&amp;quot; to erase what it did on the first search and then click &amp;quot;Scan All&amp;quot; again to rescan the program using this new data file.&lt;br /&gt;
&lt;br /&gt;
You may have to help it a bit, but once it has a proper matching open statement, read statement, form statement and dim statements for any arrays used, press the &amp;quot;Generate Layout&amp;quot; button and it will build a layout for that file.&lt;br /&gt;
&lt;br /&gt;
Finally, load the layout it built and clean up anything if you want, and consider adding better descriptions for each of the fields that you know (as it will use the variable names for both the subscripts AND descriptions in the layout).&lt;br /&gt;
&lt;br /&gt;
When you&#039;re all done, click &amp;quot;Done&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Functions to Generate Layouts from your code ====&lt;br /&gt;
&lt;br /&gt;
* [[#fnGenerateLayout_.26_fnWriteLayout|fnGenerateLayout]]&lt;br /&gt;
* [[#fnGenerateLayout_.26_fnWriteLayout|fnWriteLayout]]&lt;br /&gt;
&lt;br /&gt;
=== Code Templates ===&lt;br /&gt;
&lt;br /&gt;
One more tool FileIO has to help is the ability to generate code based on your file layouts.&lt;br /&gt;
&lt;br /&gt;
Run FileIO and this time select a file layout and press &amp;quot;Generate Code&amp;quot;. A window will pop up listing all the &amp;quot;Code Templates&amp;quot; that are available. Select one (and then select a key if it asks you - some templates require extra info). It looks like nothing happened, but the code you generated is now in your clip board. Paste it somewhere and take a look at it!&lt;br /&gt;
&lt;br /&gt;
Code Templates help us to standardize our ways of doing things, which eventually leads to more and more powerful tools we can use. Code Templates also help ensure we use cleaner code by doing some of the busy-work of writing clean code for us.&lt;br /&gt;
&lt;br /&gt;
==== Writing Code Templates ====&lt;br /&gt;
FileIO ships with several basic code templates. If you want to add your own, take a look in the filelay\templates folder (configurable in fileio.ini) and look at basic.brs. Copy it to your own program and then modify it to have your own code templates in it. Write me at gabriel.bakker@gmail.com with any questions. I want to help.&lt;br /&gt;
&lt;br /&gt;
And if you write good code templates, its easy to share them with the BR community. Anyone can download your templates and place them in this folder and they&#039;ll instantly be available for use.&lt;br /&gt;
&lt;br /&gt;
== FileIO Function Reference ==&lt;br /&gt;
&#039;&#039;The FileIO Library contains a number of other useful functions.&#039;&#039; The following functions are available and you are welcome to use them:&lt;br /&gt;
&lt;br /&gt;
=== Primary Functions ===&lt;br /&gt;
&lt;br /&gt;
==== fnOpen ====&lt;br /&gt;
fnOpen is the primary function that opens a file, and it’s used like so:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, DontSortSubs, Path$*255, Mat Descr$, Mat FieldWidths, SupressPrompt, IgnoreErrors, SuppressLog)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note that all of the parameters after MAT Form$ are optional. If you need to specify a parameter in the middle of the optional parameter group, just list zeroes and empty strings for the intervening unused parameters. &lt;br /&gt;
&lt;br /&gt;
*FileName$ - The filename of the file layout for the file you’re reading.&lt;br /&gt;
*MAT F$ - The array that will be used to hold the string data for the file.&lt;br /&gt;
*MAT F – The array that will hold the numeric data for the file.&lt;br /&gt;
*MAT Form$ - An array of form statements.&lt;br /&gt;
*InputOnly – 1 means open for input only. 0 means open for OutIn and open every key file associated with the given data file (this is because all key files need to be open for the keys to be updated on an output) (defaults to 0). Files opened for input process considerably faster than files opened for output. Furthermore when files are opened for input only, alternate key files are &#039;&#039;not&#039;&#039; opened.&lt;br /&gt;
*KeyNum – This tells the function of which key to return the file handle (defaults to 1).&lt;br /&gt;
*DontSortSubs – The function by default, when compiling the Form statement, will sort the string and numeric subs in order to allow for reading the data into an array, and this parameter would turn this functionality off. However, if you are trying to read your data without reading it into an array, you are missing out on some serious efficiencies. You should normally leave this option turned off (0). This is a totally unsupported feature, and should always be set to 0, if it is specified at all.&lt;br /&gt;
*Path$ - The path to your data files. This optional parameter can be passed in by the calling function. It is prefixed to the beginning of the paths given in the file layout files. It is useful when your data files can be in different locations depending on the state of your program.&lt;br /&gt;
*mat Description$ - This optional parameter provides a way to read the description for each field from the original file layout. If the parameter is not provided, no description data will be returned. &lt;br /&gt;
*mat Fieldwidths – This optional parameter will return an array of the calculated display field widths. This number will always be at least large enough to contain the data for this field.&lt;br /&gt;
*SuppressPrompt - This optional parameter can be used to suppress the prompt normally given when fileIO creates a file. It can have three values. A value of 0, the default, uses the setting stored in your FileIO fnSettings routine to determine weather or not to prompt on Creation of a new file. A nonzero value always suppresses the prompt. A value of 1 indicates never to create a file if the file doesn&#039;t exist. A value of 2 automatically creates the file if the file doesn&#039;t exist.&lt;br /&gt;
*IgnoreErrors - Normally when fileio opens a data file, if there are errors trying to open the file, it prints them out to the debug console and pauses so that you can try to find out whats going wrong. If you specify 1 for &amp;quot;IgnoreErrors&amp;quot; it will cause Fileio to log those errors instead, and continue loading your program. This will result in the fnOpen file function returning Zero instead of the opened file number, so if you use IgnoreErrors, you need to test to make sure that fnOpen returned a file number before you try to access the file.&lt;br /&gt;
*SuppressLog - this optional parameter can be used to suppress writing to the log file for this one specific open statement. I use it for files that will be opened all the time, for example, the menu data file on one of my customers systems. Without this boolean parameter, his log file is quickly filled up with useless information any time his employees look at his menu. I specify this optional parameter to suppress logging anything about the menu file so that I can more easily find the actual programs they&#039;ve used when looking in the logfile.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Note: When using fnOpenFile, you really want to call your local function fnOpen, which in turn calls fnOpenFile for you.&#039;&#039;&#039;&#039;&#039;  FnOpenFile is for internal use only.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  Let FFILE=FNOPEN(“FARM”,MAT FARM$,MAT FARM,MAT FORM$,0,2)&lt;br /&gt;
  Let RFILE=FNOPEN(“ROUTE”,MAT ROUTE$,MAT ROUTE,MAT FORM$,1,3)&lt;br /&gt;
  Let CFILE=FNOPEN(“CUSTOMER”,MAT CUSTOMER$,MAT CUSTOMER,MAT FORM$)&lt;br /&gt;
&lt;br /&gt;
assuming:&lt;br /&gt;
  farm.dat has 3 keys: farm.ky1, farm.ky2, farm.ky3&lt;br /&gt;
  route.dat has 4 keys: route.ky1 … route.ky4&lt;br /&gt;
  customer.dat has 2 keys: customer.ky1, customer.ky2&lt;br /&gt;
&lt;br /&gt;
This will perform the following opens and set the following variables:&lt;br /&gt;
&lt;br /&gt;
  OPEN #1: “Name=Farm.Dat, kfname=farm.ky2”,internal,outin,keyed&lt;br /&gt;
  OPEN #2: “Name=Farm.Dat, kfname=farm.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #3: “Name=Farm.Dat, kfname=farm.ky3”,internal,outin,keyed&lt;br /&gt;
  OPEN #4: “Name=Route.Dat, kfname=route.ky3”,internal,input,keyed&lt;br /&gt;
  OPEN #5: “Name=Customer.Dat,kfname=customer.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #6: “Name=Customer.Dat,kfname=customer.ky2”,internal,outin,keyed&lt;br /&gt;
  LET FFILE=1&lt;br /&gt;
  LET RFILE=4&lt;br /&gt;
  LET CFILE=5&lt;br /&gt;
&lt;br /&gt;
This will also resize the arrays, set the form statement, and create all the subscripts to make accessing the data clear and simple, as in the above example. The KEYNUM parameter is where you list the key file you would like to use for reading and writing. The extra keys are opened to ensure that all keys get updated properly when the file is changed.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  DIM FORM$(1),PRICE$(1)*255,PRICE(1),&lt;br /&gt;
  DIM DESCRIPTION$(1)*80,FIELDWIDTHS(1)&lt;br /&gt;
&lt;br /&gt;
  Let PRICEFILE=FNOPEN(“PRICE”,MAT PRICE$,MAT PRICE,MAT FORM$,0,2,0,&amp;quot;&amp;quot;,MAT DESCRIPTION$)&lt;br /&gt;
&lt;br /&gt;
Assuming the Price File layout (filelay\price) contains:&lt;br /&gt;
&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  DUMMY,          Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
 &lt;br /&gt;
This will perform the following opens and set the following variables:&lt;br /&gt;
&lt;br /&gt;
  OPEN #1: “Name=Price.Dat, kfname=Price.ky2”,internal,outin,keyed&lt;br /&gt;
  OPEN #2: “Name=Price.Dat, kfname=Price.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #3: “Name=Price.Dat, kfname=Price.ky3”,internal,outin,keyed&lt;br /&gt;
  let PRICEFILE=1&lt;br /&gt;
  let PR_FARM=1&lt;br /&gt;
  let PR_ITEM=2&lt;br /&gt;
  let PR_GRADE=3&lt;br /&gt;
  let PR_DESCR=4&lt;br /&gt;
  let PR_PRICE=1&lt;br /&gt;
  let PR_COST=2&lt;br /&gt;
  let PR_XOPRICE=3&lt;br /&gt;
  let PR_XOCOST=4&lt;br /&gt;
  let PR_MOPRICE=5&lt;br /&gt;
  let PR_MOCOST=6&lt;br /&gt;
  let PR_VOPRICE=7&lt;br /&gt;
  let PR_VOCOST=8&lt;br /&gt;
  MAT FORM$(1)&lt;br /&gt;
  MAT PRICE$(4)&lt;br /&gt;
  MAT PRICE(8)&lt;br /&gt;
  MAT DESCRIPTION$(12)&lt;br /&gt;
  MAT FIELDWIDTHS(12)&lt;br /&gt;
  let FORM$(1)=CFORM$(”form C 4,C 4,C 4,POS 74,C 30,POS 50,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2”)&lt;br /&gt;
  let Description$(1)= “Farm Code (or blank)”&lt;br /&gt;
  let Description$(2) = “Item Code”&lt;br /&gt;
  let Description$(3) = “Quality”&lt;br /&gt;
  let Description$(4) = “Description of Price Rule”&lt;br /&gt;
  let Description$(5) = “Default Price”&lt;br /&gt;
  let Description$(6) = “Default Cost”&lt;br /&gt;
  let Description$(7) = “Default Christmas Price”&lt;br /&gt;
  let Description$(8) = “Default Christmas Cost”&lt;br /&gt;
  let Description$(9) = “Default Mothers D Price”&lt;br /&gt;
  let Description$(10) = “Default Mothers D Cost”&lt;br /&gt;
  let Description$(11) = “Default Valentine Price”&lt;br /&gt;
  let Description$(12) = “Default Valentine Cost”&lt;br /&gt;
  let FieldWidths(1) = 4&lt;br /&gt;
  let FieldWidths(2) = 4&lt;br /&gt;
  let FieldWidths(3) = 4&lt;br /&gt;
  let FieldWidths(4) = 30&lt;br /&gt;
  let FieldWidths(5) = 8&lt;br /&gt;
  let FieldWidths(6) = 8&lt;br /&gt;
  let FieldWidths(7) = 8&lt;br /&gt;
  let FieldWidths(8) = 8&lt;br /&gt;
  let FieldWidths(9) = 8&lt;br /&gt;
  let FieldWidths(10) = 8&lt;br /&gt;
  let FieldWidths(11) = 8&lt;br /&gt;
  let FieldWidths(12) = 8&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
There are a few things I’d like to point out about the example above. First, you will notice that the form statement jumps around to put all the strings first, and then the numbers last. This is why it has a “POS 74, C 30,POS 50”. Then notice that the subscripts for the string variables are 1 .. 4, and the subscripts for the numbers are 1 .. 8. Finally, the order of the Description and FieldWidth fields also match the sorted positioning of the Form Statement.&lt;br /&gt;
&lt;br /&gt;
The reason that we sort our form statements is so that BR will allow us to read the file into arrays by saying:&lt;br /&gt;
&lt;br /&gt;
  Read #pricefile, using form$(pricefile) : mat price$, mat price&lt;br /&gt;
&lt;br /&gt;
Without resorting, the above statement would give a conversion error as BR attempted to put the PR_PRICE field inside mat price$(4). However, because we have reordered the form statement, we are able to read them safely into two arrays, and then we will be able to use the values without caring what position they are in the file, by simply saying PRICE$(PR_DESCRIPTION) when we want the description, and PRICE(PR_PRICE) when we want the pr_Price field.&lt;br /&gt;
&lt;br /&gt;
Another thing you may notice about the above example is that it gives the calculated display length for the numeric fields as 8, when on the disk (and in the file layout) they are listed as BH 3.2. The reason for this is the program looks at the BH 3, and figures that a number that takes up 3 bytes on disk has a potential maximum size of 256**3 or 16,777,216, and therefore will need up to 8 characters of screen display space to view. &lt;br /&gt;
&lt;br /&gt;
Finally, note that any field with a form statement of X is ignored by the library, except that the blank space is used when building the FORM statement.&lt;br /&gt;
&lt;br /&gt;
==== fnCloseFile ====&lt;br /&gt;
This function will close the specified file number and all keys that were opened with the file.  The purpose of this function is to facilitate the closing of the extra keys that are opened when you open a file for OutIn with the library. There is no need to use this for files opened for input because it is easier to just close the file directly. Secondary keys are not opened by FileIO for files opened for input only. &lt;br /&gt;
&lt;br /&gt;
You must give the function the name of the file layout. It uses this information to determine how many keys were opened, and how many it must therefore close. &lt;br /&gt;
&lt;br /&gt;
Then it basically starts at the file number you gave it, and closes the next X files that were opened with the same file name as this, where X is the number of keys associated with this file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCloseFile(filenumber,filelay$;path$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FileNumber – The filenumber of the file you are trying to close.&lt;br /&gt;
*FileLay$ - The name of the file layout for this file. This is used to determine how many keys the file would have been opened with and therefore how many we now need to close.&lt;br /&gt;
*Path$ - Optional Alternate Path. Use to close files that were opened using the open file&#039;s optional alternate path parameter.&lt;br /&gt;
&lt;br /&gt;
==== fnGetFileNumber ====&lt;br /&gt;
FnGetFileNumber is a simple function to find a valid unused file handle. If you use this function in all of your programs, they will become much more portable, as you will never have to worry about your file handles fighting with each other. The function will return 0 if no free file number was found (but with 999 of them available now, I have never seen it happen).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnGetFileNumber(;X,Count)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*X – This optional parameter will specify where to start looking.&lt;br /&gt;
*Count - This optional parameter will specify how many file numbers to find in a row. If count is 3, then fnGetFileNumber will return the first filenumber in the first gap of three unused file numbers that it finds.&lt;br /&gt;
&lt;br /&gt;
=== File Reading Helper Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions perform various useful calculations to aid in interacting with data files when you&#039;re using fileio.&lt;br /&gt;
&lt;br /&gt;
==== fnBuildKey$ ====&lt;br /&gt;
This function will return the key for a given record in a data file. It actually reads the file layout and builds the key to match the layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnBuildKey$(Layout$, Mat F$, Mat F; Keynum)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the name of the data file to build the key for.&lt;br /&gt;
*Mat F$ - the string array of the file object&lt;br /&gt;
*Mat F - the numeric array of the file object&lt;br /&gt;
*KeyNum - This optional parameter specifies which of the key files in the given layout the key should be built for.&lt;br /&gt;
&lt;br /&gt;
To use this, you want some code like in the following example:&lt;br /&gt;
&lt;br /&gt;
  mat customer$=(&amp;quot;&amp;quot;) : mat Customer=(0)&lt;br /&gt;
  let customer$(cu_name)=CustName$&lt;br /&gt;
  let customer$(cu_phone)=CustPhone$&lt;br /&gt;
  read #customer, using form$(Customer), key=fnBuildKey$(&amp;quot;customer&amp;quot;,mat Customer$,mat Customer,2) : mat Customer$, mat Customer nokey KeyNotFound&lt;br /&gt;
  ! The above code assumes that the second key of the Customer file is based on the Name and Phone fields.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
By using this logic you are able to avoid directly specifying the key in your code - which means that even if the key changes in the future, as long as your code specifies enough information, it will still find the correct key. In our example, even if we dropped the phone number from the key in the future, or even if we expand the length of the Customer Name field, our code would still work and fnBuildKey$ would still build the correct key without us having to look at or change our code again.&lt;br /&gt;
&lt;br /&gt;
This kind of reasoning is central to the fileio system, which, when implemented properly, ensures that you can change your data files in any way you need to in the future, without breaking your existing programs.&lt;br /&gt;
&lt;br /&gt;
==== fnUniqueKey ====&lt;br /&gt;
This function tests to see if a given key is unique to the specified file. This function is very useful for situations where you need to ensure that the user-entered key is unique.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnUniqueKey(Fl,key$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file number of the opened file.&lt;br /&gt;
*Key$ - This is the key to test. If this key is the key for a preexisting record in the file, the function will return false. If this key can not be found in the file, the function will return true.&lt;br /&gt;
&lt;br /&gt;
==== fnMakeUniqueKey$ ====&lt;br /&gt;
This function generates a unique key for a given file. This is useful if you do not care what the key is, but it needs to be unique. I use this function in situations where the user never needs to know what the given key is. &lt;br /&gt;
&lt;br /&gt;
This function reads the key length for the given file. Then it returns a string that is the right length, which is generated by counting in binary until a key is found that does not appear in the file. The first key found for a 4 byte key field would be chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0). If that key was already in use in the file, the function would return chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(1). If that one was also in use, it would then try chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(2), and so on until it found one that wasn’t in use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnMakeUniqueKey$(fl)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – This is the file number of the opened file for the desired key.&lt;br /&gt;
&lt;br /&gt;
==== fnKey$ ====&lt;br /&gt;
This function formats the key for the given file number. All it does is ensure the key is the correct length. You should use fnBuildKey$ instead to properly build the correct key for the record you want to read.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnKey$(FileNumber, Key$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileNumber - the file number we are formatting the key for&lt;br /&gt;
*Key$ - the key we are trying to format.&lt;br /&gt;
&lt;br /&gt;
==== fnNotInFile ====&lt;br /&gt;
This function will determine if a non-key element in a line is unique. It works almost exactly like fnUniqueKey specified above, except that it allows you to enter the subscript value of the element you are checking for uniqueness. You can use this to look for uniqueness in any field, not just in the key field. Additionally, the search engine used by this function looks for a partial match, and will only return true if the given string is not found anywhere in the specified element for the given file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnNotInFile(string$*100,filename$,sub)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - Value to check for uniqueness in this file.&lt;br /&gt;
*Filename$ - This is the name of the file layout of the file you want to check. This file does not have to be open in order for you to search it, because the function will open it for you.&lt;br /&gt;
*Sub – This is the subscript value of the element you are checking.&lt;br /&gt;
&lt;br /&gt;
==== fnSortKeys ====&lt;br /&gt;
This function takes an array of Primary Keys indicating records in the data file, and resorts it into the order you would have expected using one of the other keys for your data file.&lt;br /&gt;
&lt;br /&gt;
For example: Lets say you had a customer file, and the first key was Customer Code and the second key was Customer Last Name. This function would take an array of Customer Codes and sort it into Last Name order.&lt;br /&gt;
&lt;br /&gt;
This function requires the file to already be opened (which is usually the case when you have an array of keys from that file).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnSortKeys(mat Keys$,Layout$,DataFile,mat F$,mat F,mat Form$;KeyNum)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Keys$ - the array of keys. These keys are based on whatever key the file was opened with in DataFile.&lt;br /&gt;
*Layout$ - the file layout for the file.&lt;br /&gt;
*DataFile - the open file number matching the key file that matches mat Keys$.&lt;br /&gt;
*mat F$ - array sized to hold the strings from the data file. This is the array you get back from fnOpen.&lt;br /&gt;
*mat F - array sized to hold the numerics from the data file. This is the array you get back from fnOpen.&lt;br /&gt;
*mat Form$ - array of form statements, that you get back from fnOpen.&lt;br /&gt;
*KeyNum - This is the key that we&#039;ll sort based on. If not given, the first key listed in the layout is assumed.&lt;br /&gt;
&lt;br /&gt;
=== File Reading Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions actually read information from your data file and return it. These functions can be used to simplify the logic in your programs for many common tasks.&lt;br /&gt;
&lt;br /&gt;
==== fnReadAllKeys ====&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record into (a) dynamically dimensioned array(s). For example, I could tell it to give me the Inventory Code for every inventory item in my database in one array, while placing the Inventory Description (name) for each item into the corresponding position in another array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadAllKeys(Fl,mat f$,mat f,mat fm$,sub1,mat out1$;sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – The file handle for the already opened file in question.&lt;br /&gt;
*mat F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array&lt;br /&gt;
*mat out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*mat out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If I wanted to implement the above example, I would say:&lt;br /&gt;
&lt;br /&gt;
  FnReadAllKeys(InventFile,mat Invent$,mat Invent,mat Form$,IN_Code,mat InvtList$,IN_Name,mat InvtNames$)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnReadMatchingKeys ====&lt;br /&gt;
&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record where the key matches the specified key into (a) dynamically dimensioned array(s). This function is the same as the above function except this one will filter the results, returning only those records where the key matches the specified key.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadMatchingKeys(Fl,mat f$,mat f,mat fm$,key$,keysub,sub1,mat out1$;sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*mat F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Key$ - Only records where the key field matches key$ will be returned.&lt;br /&gt;
*Keysub – This tells the function which element is the key element for this particular file number.&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*mat out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnReadAllNewKeys ====&lt;br /&gt;
&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record that isn’t already there into (a) dynamically dimensioned array(s). This function is the same as the above function, except this one will filter the results returning only those records that don’t already exist in the array (eliminating duplicates).&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;FnReadAllNewKeys(Fl,mat f$,mat f,mat fm$,sub1,mat out1$; dont_reset,sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*MAT F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Dont_reset – By default the array will clear the contents of the arrays that are passed in. This Boolean flag will instruct the function to not empty the passed in arrays.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*MAT out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
==== fnReadFilterKeys ====&lt;br /&gt;
&lt;br /&gt;
This function by Mikhail Zheleznov is a modification of the above functions. Like its predecessors, it reads an entire file, populating the specified arrays with data from all or some of the records in the file. The given subscripts specify which fields to return from each record. The key given specifies search criteria for the records. The filter specifies filtering criteria that can be preformed on the data before it is returned. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadFilterKeys(Fl,Mat F$,Mat F,Mat Fm$,Key$,Keyfld,Sub1,Mat Out1$;Filter$,Filter_Sub,Readlarger,Sub2,Mat Out2$, Sub3, Mat Out3$, Sub4,Mat Out4$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*MAT F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Key$ - The key to search for in the read statements&lt;br /&gt;
*Keyfld – the subscript of the key field in the data file. This must match the key field specified in the data file otherwise the function won’t work.&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Filter$ – This optional parameter identifies matches to search for in the records. It works in conjunction with Filter_Sub&lt;br /&gt;
*Filter_Sub – This parameter specifies which field to look for in the records for matches to Filter$. Only records which have Filter$ in the specified field will be returned.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*MAT out2$ - Array in which to return the second (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
*Sub3 – Subscript of the element to return in the third array. This is optional. If it is specified, you must give MAT out3$, or BR will return an error.&lt;br /&gt;
*MAT out3$ - Array in which to return the third (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub3 is given (non-zero). This parameter will not be used if Sub3 is not given or is given as 0.&lt;br /&gt;
*Sub4 – Subscript of the element to return in the fourth array. This is optional. If it is specified, you must give MAT out4$, or BR will return an error.&lt;br /&gt;
*mat out4$ - Array in which to return the fourth (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub4 is given (non-zero). This parameter will not be used if Sub4 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
This function was written by Mikhail Zheleznov for the fileIO library.&lt;br /&gt;
&lt;br /&gt;
==== fnReadDescription$ ====&lt;br /&gt;
&#039;&#039;fnReadDescription$(Fl,Subscript,key$,mat F$,mat F,mat Form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – File Handle for file to use (Route File).&lt;br /&gt;
*Subscript – Index of field in record to use (should be taken from file layout) (RT_NAME, which should equal 2 after opening routefile (unless we change the file layout later)).&lt;br /&gt;
*key$ - Item that should match a key in this file somewhere (in this case it is the route code from the farm record).&lt;br /&gt;
*mat F$ &amp;amp; mat F - Work Variables to hold a file record from the file we are reading they have to be dimensioned properly, which is why we use our colorcat$ and our colorcat for these parameters.&lt;br /&gt;
*mat Form$ - This will need to be our array of form statements, so the function can read the file properly.&lt;br /&gt;
&lt;br /&gt;
Lets take a look at how this function works:&lt;br /&gt;
&lt;br /&gt;
In the example program I used above, I am reading the Color File to get details about each color. The color file contains a colorcat code field, but I want to display the colorcat description. The colorcat file contains a few details about a color category, and it is indexed based on colorcat code:&lt;br /&gt;
&lt;br /&gt;
  route.dat, RT_&lt;br /&gt;
  route.key, CODE&lt;br /&gt;
  recl=512&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE,           Routing Code,                C    6&lt;br /&gt;
  NAME,           Routing Name Description,    C   30&lt;br /&gt;
  MOFT,           T/A/C (truck/air/courier),   C    1&lt;br /&gt;
  SHIPPINGDAY,    Day of Week for Shipping,    C    7&lt;br /&gt;
&lt;br /&gt;
Now, as you know, in the above example, we have already opened the ColorCat File, and we have opened and read a Color record.&lt;br /&gt;
 &lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  30120       read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore&lt;br /&gt;
  30180       LET ccode$=color$(CO_CODE) !:&lt;br /&gt;
              LET Name$=color$(CO_NAME)&lt;br /&gt;
&lt;br /&gt;
Now all that’s left to do is to take the Color File’s ColorCat code and use it to look up the ColorCat File’s description.&lt;br /&gt;
&lt;br /&gt;
  30190 LET ColorCat$ = fnReadDescription$(ColorCatFile, CC_NAME, Color$(CO_CATEGORY),&lt;br /&gt;
    mat ColorCat$, mat ColorCat, mat form$)&lt;br /&gt;
&lt;br /&gt;
==== fnReadUnopenedDescription$ ====&lt;br /&gt;
This function accomplishes the same thing as fnReadDescription except that it opens the data file for you. It is slower then FnReadDescription$, but it is easier to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadUnopenedDescription$(Layout$,key$*255;Field)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are reading&lt;br /&gt;
*key$ - the value of the key field in the record to be read&lt;br /&gt;
*Field - the element of the data file to return. If not given, this defaults to 2, so sometimes it is a good idea to design your data files so that string field number two is a descriptive field, like Name or Description.&lt;br /&gt;
&lt;br /&gt;
This function only works on the first key file for each data file. This function is a convenience function but it is slow because it opens the file and closes it for each call. Opening a file is one of the most time consuming program operations.&lt;br /&gt;
&lt;br /&gt;
==== fnReadNumber ====&lt;br /&gt;
&lt;br /&gt;
fnReadNumber does the same thing that ReadDescription does except it reads a numeric field instead of a description.&lt;br /&gt;
&lt;br /&gt;
Lets take a look at how this function works:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadNumber(Fl,subscript,key$,mat F$,mat F,mat fm$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – File Handle for file to use (Route File).&lt;br /&gt;
*Subscript – Index of field in record to use (should be taken from file layout).&lt;br /&gt;
*Key$ - Item that should match a key in this file somewhere.&lt;br /&gt;
*mat F$ &amp;amp; mat F - Work Variables to hold a file record from the file we are reading. They have to be dimensioned properly by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat Fm$ - This will need to be our array of form statements, so the function can read the file properly.&lt;br /&gt;
&lt;br /&gt;
==== fnReadUnopenedNumber ====&lt;br /&gt;
This function accomplishes the same thing as fnReadNumber except that it opens the data file for you. It is slower then FnReadNumber, but it is easier to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadUnopenedNumber(Layout$,key$*255;Field)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are reading&lt;br /&gt;
*key$ - the key of the record to be read&lt;br /&gt;
*Field - the element of the data file to return. If not given, this defaults to 2, so sometimes it is a good idea to design your data files so that string field number two is a descriptive field, like Name or Description.&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelativeDescription$ ====&lt;br /&gt;
This function is the same as fnReadDescription$ but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelativeDescription$(FileNumber,SubscriptToRead,RecordNumber,mat F$,mat F,mat form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Filenumber - The file number of the open data file&lt;br /&gt;
*SubscriptToRead - The subscript to read&lt;br /&gt;
*RecordNumber - the Record number to read&lt;br /&gt;
*mat F$ and mat F - the arrays to hold the data. They must match the dimensions and should be set with [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat form$ - the forms array is also set by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelUnopenedDescription$ ====&lt;br /&gt;
This is the same as ReadUnopenedDescription$ but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelUnopenedDescription(Layout$,RecordNumber;Field)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*RecordNumber - the record to read&lt;br /&gt;
*Field - the field subscript to read&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelativeNumber ====&lt;br /&gt;
This is the same as fnReadNumber but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelativeNumber(FileNumber,SubscriptToRead,RecordNumber,mat F$,mat f,mat Form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Filenumber - The file number of the open data file&lt;br /&gt;
*SubscriptToRead - The subscript to read&lt;br /&gt;
*RecordNumber - the Record number to read&lt;br /&gt;
*mat F$ and mat F - the arrays to hold the data. They must match the dimensions and should be set with [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat form$ - the forms array is also set by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelUnopenedNumber ====&lt;br /&gt;
This is the same as fnReadUnopenedNumber but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelUnopenedNumber(LayoutName$,RecordNumber;Field)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*RecordNumber - the record to read&lt;br /&gt;
*Field - the field subscript to read&lt;br /&gt;
&lt;br /&gt;
==== fnReadRecordWhere$ ====&lt;br /&gt;
This function returns the record where the given element matches the given value. It does not depend on any key files, and it can be used to locate a record based on any element. However, it loops through the entire data file to do this and it could be a bit slow for large data files. This function opens the file for you, so the file does not have to be already opened.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadRecordWhere$(Layout$,SearchSub,SearchKey$*255,ReturnSub)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are searching&lt;br /&gt;
*SearchSub - Subscript of the element to look in&lt;br /&gt;
*SearchKey$ - The value we are looking for&lt;br /&gt;
*ReturnSub - Subscript of the element to return&lt;br /&gt;
&lt;br /&gt;
=== FileIO Utility Functions ===&lt;br /&gt;
==== fnDataCrawler ====&lt;br /&gt;
This function launches the Data Crawler as a function, so you can make your own programs link to it. Special thanks to Mikhail Zheleznov for turning the DataCrawler into a library function.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDataCrawler(Layout$;SRow$,SCol$,Rows$,Cols$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnDataEdit ====&lt;br /&gt;
This function is the same as fnDataCrawler only it opens a Grid for editing.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDataCrawler(Layout$;SRow$,SCol$,Rows$,Cols$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnShowData ====&lt;br /&gt;
&lt;br /&gt;
This function builds a list or a grid in a floating window that is tied to a data file. It uses the same function that the datacrawler uses, but its much more customizable. All other datacrawler functions are just wrappers for this one.&lt;br /&gt;
&lt;br /&gt;
The first parameter is the only required parameter.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;def library fnShowData(FileLay$;Edit,sRow,sCol,Rows,Cols,KeyNumber,Caption$*127,Path$*255,KeyMatch$*255,SearchMatch$*255,CallingProgram$*255,mat Records,mat IncludeCols$,mat IncludeUI$,mat ColumnDescription$,mat ColumnWidths,mat ColumnForms$,DisplayField$*80,mat FilterFields$,mat FilterForm$,mat FilterCompare$,mat FilterCaption$,mat FilterDefaults$,mat FilterKey)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileLay$ - the file layout you want to display&lt;br /&gt;
*Edit - 1 for Edit (Grid) and 0 for View (Listview)&lt;br /&gt;
*sRow, sCol - the start position. if not given, its centered. If given but out of bounds, they&#039;ll be automatically adjusted to fit the grid on the screen.&lt;br /&gt;
*Rows, Cols - the size. If not given, defaults to fullscreen. If given but not big enough to fit the UI elements you request, they&#039;re automatically adjusted to fit everthing.&lt;br /&gt;
*KeyNumber - the Key to use when reading the data, used with other parameters. If not given, the file is read Relative for faster performance. Required if KeyMatch$ is given.&lt;br /&gt;
*Caption$ - the Caption to display, defaults to FileIO&#039;s Datacrawler&lt;br /&gt;
*Path$ - Alternate path to use for data files (Prepended to the name found in the layout)&lt;br /&gt;
*KeyMatch$ - Show only records that match this key. You can use Partial Keys. If this parameter is given, you must also give KeyNumber (above).&lt;br /&gt;
*SearchMatch$ - Show only records that contain this substring in them anywhere&lt;br /&gt;
*CallingProgram$ - used for logging purposes, pass in the system function Program$&lt;br /&gt;
*mat Records - Show only these records in the Grid. Use it to control exactly what the user sees.&lt;br /&gt;
*mat IncludeCols$ - Show only these columns. These column names must match the subscript names from the file layout.&lt;br /&gt;
*mat IncludeUI$ - Which UI Options to show. Build this array with one element for each optional UI element to include. Explanations of UI elements follow:&lt;br /&gt;
**&amp;quot;ColumnsButton&amp;quot; - adds a Select Columns button that the user can use to modify which columns appear on the list.&lt;br /&gt;
**&amp;quot;ExportButton&amp;quot; - adds an Export to CSV button that exports the data to a CSV file.&lt;br /&gt;
**&amp;quot;ImportButton&amp;quot; - adds an Import from CSV button that imports from the CSV file.&lt;br /&gt;
**&amp;quot;AddButton&amp;quot; - adds a button that can be used to add records to the data file.&lt;br /&gt;
**&amp;quot;SaveButton&amp;quot; - adds a button allowing the user to save changes&lt;br /&gt;
**&amp;quot;DeleteButton&amp;quot; - adds a button allowing the user to delete a row&lt;br /&gt;
**&amp;quot;KeyButton&amp;quot; - adds a button allowing the user to jump to a specified position by key or by record number (depending on if the file is opened keyed or not)&lt;br /&gt;
**&amp;quot;QuitButton&amp;quot; - adds a Quit button to the screen (the Esc key also quits)&lt;br /&gt;
**&amp;quot;Search&amp;quot; - adds a case insensitive search box to the screen.&lt;br /&gt;
**&amp;quot;Border&amp;quot; - adds a border around the screen&lt;br /&gt;
**&amp;quot;Caption&amp;quot; - adds a caption. (If you specify a caption, this is automatically turned on. If you don&#039;t specify a caption but turn on caption here, then FileIO uses the default FileIO data crawler caption.&lt;br /&gt;
**&amp;quot;Recl&amp;quot; - adds the Recl to the caption&lt;br /&gt;
**&amp;quot;Position&amp;quot; - adds the positions to the field descriptions in the column headings.&lt;br /&gt;
*mat ColumnDescription$ - Show these captions. If blank, use the descriptions from the layout&lt;br /&gt;
*mat ColumnWidths - Use these widths for the data, if not given, calculate from the file layout&lt;br /&gt;
*mat ColumnForms$ - Display Format for the data, including DATE and FMT and PIC&lt;br /&gt;
*mat DisplayField$ - Counter Field to display on the Loading Window. If its a field with an associated DATE ColumnForms$ value, that column form will be used when displaying the Counter Field. It can be any of the following:&lt;br /&gt;
**REC - this will display the current &amp;quot;REC/LREC&amp;quot; data in the loading window.&lt;br /&gt;
**READCOUNT - this will display the &amp;quot;Record Count / LREC&amp;quot; in the loading window.&lt;br /&gt;
**FINDCOUNT - this will display the number of records that match the current search criteria by itself in the loading window.&lt;br /&gt;
**A Field Name - one of your field names will display that field value in the loading window&lt;br /&gt;
**A string literal - anything else will display as a string in the loading window, so you could put something like &amp;quot;Loading, please wait&amp;quot; here and it will display.&lt;br /&gt;
*mat FilterFields$ - Contains the subscript of the field to compare to&lt;br /&gt;
*mat FilterForm$ - Contains the format of the field to compare to&lt;br /&gt;
*mat FilterCompare$ - Contains the comparison type (&amp;quot;&amp;lt;&amp;gt;&amp;quot; or &amp;quot;&amp;gt;&amp;quot; or &amp;quot;=&amp;quot; or &amp;quot;&amp;gt;=&amp;quot; or &amp;quot;*&amp;quot;) (* means do a substring search)&lt;br /&gt;
*mat FilterCaption$ - The caption for the filter box&lt;br /&gt;
*mat FilterDefaults$ - The default value for the filter information&lt;br /&gt;
*mat FilterKey - The action to use when filtering the data this way (0 means simple exclude, 1 means start here, -1 means stop here)&lt;br /&gt;
**The final five arrays can be used to add user filter boxes to the data grid. You need one element in each array for every custom user filter box on the screen.&lt;br /&gt;
&lt;br /&gt;
==== fnCSVImport ====&lt;br /&gt;
&lt;br /&gt;
This function calls the FileIO Import routine, the same one that you get from the Datacrawlers Import Button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCsvImport(Layout$*64;SuppressDialog,FileName$*300,ImportModeKey)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout to import into&lt;br /&gt;
*SupressDialog - 1 to Supress the Import Dialog&lt;br /&gt;
*FileName$ - the name of the CSV file (Required if Dialog is Suppressed)&lt;br /&gt;
*ImportModeKey - the Import Mode Key (Required if Dialog is Suppressed)&lt;br /&gt;
**-1 - Add all records to the file&lt;br /&gt;
**0 - Update by Record Number (The file must contain a RecNum column and it must be first)&lt;br /&gt;
**1+ - Any positive number means Update by that Key (as listed in the layout).&lt;br /&gt;
&lt;br /&gt;
==== fnCSVExport ====&lt;br /&gt;
&lt;br /&gt;
This function exports a data file to a CSV file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCsvExport(Layout$*64;SuppressDialog,Filename$*300,IncludeRecNums,KeyNumber,StartKey$,KeyMatch$,Startrec,mat Records,SearchMatch$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The File Layout to Export&lt;br /&gt;
*SuppressDialog - (1 to Suppress the Export Dialog, 0 to show it)&lt;br /&gt;
*Filename$ - the output file name (Required if SuppressDialog is 1)&lt;br /&gt;
*IncludeRecNums - Include a column with the Record Numbers in it&lt;br /&gt;
*KeyNumber - Use this key when reading the data for export&lt;br /&gt;
*StartKey$ - Start with the record that matches StartKey$&lt;br /&gt;
*KeyMatch$ - Export only the record(s) that match KeyMatch$&lt;br /&gt;
*StartRec - Start with this Record Number&lt;br /&gt;
*mat Records - Export only these records&lt;br /&gt;
*SearchMatch$ - Export only records containing this search string anywhere in them&lt;br /&gt;
&lt;br /&gt;
==== fnGenerateLayout &amp;amp; fnWriteLayout ====&lt;br /&gt;
&lt;br /&gt;
This function calls on the Generate File Layout Wizard to generate and save the layout indicated by the parameters you give it. You must give it the same valid parameters that you would have come up with if you worked through the layout wizard the normal way, by running FileIO directly and choosing &amp;quot;Generate Layout&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can also bypass the automatic parsing and generate a layout by specifying all the data directly and using fnWriteLayout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnGenerateLayout(mat OpenStrings$, ReadString$*999, FormString$*20000, DimString$*999; DisplayFile)&#039;&#039;&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat OpenString$ - array of all the open strings for the given file from one of your old programs.&lt;br /&gt;
*mat ReadString$ - solid read statement from one of your old programs reading the entire record, (or at least everything you want in the layout).&lt;br /&gt;
*mat FormString$ - the form statement that goes with the ReadString$ (practice using the Generate Layout Wizard the normal way for details)&lt;br /&gt;
*mat DimString$ - the string containing Dim statements for each array mentioned in ReadString$. We need this to know how big the arrays are.&lt;br /&gt;
*DisplayFile - if True (1), it will Display the new layout in notepad when its done creating it. If false (0), it will simply create the file.&lt;br /&gt;
&lt;br /&gt;
fnGenerateLayout takes all the above information and parses it into a layout, then calls fnWriteLayout to actually write the layout.&lt;br /&gt;
&lt;br /&gt;
If you already know the information you want to put in the layout, its more direct to call fnWriteLayout below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnWriteLayout(Name$,FileName$*127,VER,PRE$,MAT KFNAME$,MAT KDESCRIPTION$,MAT SUBS$,MAT DESCR$,MAT FORM$;RECL,MAT EXTRA$,DISPLAYFILE)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Name$ - the name of the new layout&lt;br /&gt;
*FileName$*127 - the name of the data file&lt;br /&gt;
*Ver - the version of the data file&lt;br /&gt;
*Pre$ - the prefix to use for the data file&lt;br /&gt;
*mat KfName$ - array of all the keys for the file&lt;br /&gt;
*mat Kdescription$ - array of the subscripts that each key is based on&lt;br /&gt;
*mat Subs$ - the subscript for each field in the file&lt;br /&gt;
*mat Descr$ - the descriptions for each field in the file&lt;br /&gt;
*mat Form$ - the form specs for each field in the file&lt;br /&gt;
*Recl - (optional) the record length of the file&lt;br /&gt;
*mat Extra$ - (optional) Additonal Information for each field in the file, placed in the Comments column of the new layout. This column is ignored by standard fileio processing.&lt;br /&gt;
DisplayFile - if True, open the file in Notepad after it has been created.&lt;br /&gt;
&lt;br /&gt;
=== File System Utility Functions ===&lt;br /&gt;
These functions perform other tasks that aid with interacting with the file system.&lt;br /&gt;
&lt;br /&gt;
==== fnGetFileDateTime$ ====&lt;br /&gt;
This does a directory listing to determine the Last Modified Date and Time of the given file. You pass it a file name, not a file layout, and it can be used on any file. Its not limited to BR internal files.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let FileDate$=fnGetFileDateTime$(Filename$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnCopyFile ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCopyFile(FromFile$*255,ToFile$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FromFile$ - The file to copy.&lt;br /&gt;
*ToFile$ - The destination file name including path.&lt;br /&gt;
&lt;br /&gt;
This function copies any file, by opening it as an external file and reading and writing the data to the destination file. The advantage of this technique, over using the BR copy command, is this routine is more reliable when run on client server where you may be transferring large files from one side to the other over the internet.&lt;br /&gt;
&lt;br /&gt;
This fnCopyFile also has a progress bar that displays as the file is transferred, so the user knows your software is busy.&lt;br /&gt;
&lt;br /&gt;
This function works over Client Server. Under Client Server, specify @: at the beginning of your filename, to specify that the file is on the client. If the file is on the server, simply leave the @: off. See the chapter on [[Copy#Client_Server|using BR&#039;s copy command under Client Server]] for more details on the &amp;quot;@:&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This function&#039;s parameters and syntax are modeled off of the built in BR copy command, and like that one, this should work for local transfers, LAN transfers, or even internet transfers. This function will work better for internet transfers then the built in BR Copy Command, however. &lt;br /&gt;
&lt;br /&gt;
==== fnCopyDataFiles ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCopyDataFiles(DestinationFolder$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*DestinationFolder$ - the folder to copy your data files to.&lt;br /&gt;
&lt;br /&gt;
This function reads your file layouts and makes a copy of every data file (and key file) in your system to the destination folder, utilizing fnCopyFile above, for better performance and reliability when running over the internet, as well as a progress bar for each individual file.&lt;br /&gt;
&lt;br /&gt;
It also displays a listview while its copying so you can watch the progress while its transferring your data files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This can be used for making backups of your BR data, or for transferring the latest data onto a laptop for access to it while you&#039;re on the road away from the internet.&lt;br /&gt;
&lt;br /&gt;
==== fnReIndex ====&lt;br /&gt;
&lt;br /&gt;
This function reindexes a single data file&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReIndex(DataFile$*255;CallingProgram$*255,IndexNum,Path$*25)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Datafile$ - the file layout of the file to index&lt;br /&gt;
*CallingProgram$ - used for logging, pass Program$ in here&lt;br /&gt;
*IndexNum - The index to rebuild - if not given, rebuilds all indexes&lt;br /&gt;
*Path$ - the optional alternate path to use for rebuilding the data file.&lt;br /&gt;
&lt;br /&gt;
==== fnReIndexAllFiles ====&lt;br /&gt;
&lt;br /&gt;
This function reindexes all your data files. It doesn&#039;t require any parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReIndexAllFiles&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnUpdateFile ====&lt;br /&gt;
This function checks and Updates a data file if it needs to be updated, by opening and then closing the data file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnUpdateFile(FileLayout$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileLayout$ - The name of the file to update&lt;br /&gt;
&lt;br /&gt;
==== fnRemoveDeletes ====&lt;br /&gt;
&lt;br /&gt;
This function, written by Susan Smith, removes deleted records by copying the file with the -D option.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnRemoveDeletes(LayoutName$*255;Path$*255,CallingProgram$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*LayoutName$ - the file layout&lt;br /&gt;
*Path$ - Optional Alternate Path&lt;br /&gt;
*CallingPRogram$ - used for logging, pass Program$ in here&lt;br /&gt;
&lt;br /&gt;
=== Layout Interrogation ===&lt;br /&gt;
Layout interrogation functions are provided for convenience and to enable future dictionary changes without disrupting any programs that interrogate it.&lt;br /&gt;
&lt;br /&gt;
==== fnMakeSubProc ====&lt;br /&gt;
This function obtains the subscript assignments that were assigned by fnOpen according to the file layout. The fnMakeSubProc$ routine obtains the subscript assignments without actually opening the file. This is useful when a file record is passed as arrays into a library function in another program, or when you chained to another program and you need to know how to reach the data in the arrays without actually reopening the file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnMakeSubProc(filelay$;mat Subscripts$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FileLay$ - The name of the file layout from which to read the subscripts.&lt;br /&gt;
*mat Subscripts$ - If you give this optional array, fnMakeSubProc passes the subscripts back in this array rather then in the subs.$$$ file. This is much faster and helps avoid sharing conflicts.&lt;br /&gt;
&lt;br /&gt;
When this routine returns, you can set the subscripts in your program by executing every element of the Subscripts$ array in a for/next loop.&lt;br /&gt;
&lt;br /&gt;
If you did not pass in a subscripts array, then the a procedure file named subs.$$$ is created. If you proc that file, the proper subscripts will be set.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutArrays ====&lt;br /&gt;
This function reads the fields in a file layout into arrays. You call it like the following&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLayoutArrays(filelay$,&amp;amp;prefix$;mat SSubs$, mat NSubs$, mat SSpec$, mat NSpec$,mat SDescription$, mat NDescription$,Mat Spos,Mat Npos)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*filelay$ - the name of the layout to read&lt;br /&gt;
*prefix$ - the return value for the prefix for the file&lt;br /&gt;
*mat SSubs$ - the return value for all the string subscripts in the layout&lt;br /&gt;
*mat NSubs$ - the return value for the numeric subscripts in the layout&lt;br /&gt;
*mat SSpec$ - the return value for the string fields specs&lt;br /&gt;
*mat NSpec$ - the return value for the numeric fields specs&lt;br /&gt;
*mat SDescription$ - the return value for the Descriptions of the String Specs&lt;br /&gt;
*mat NDescription$ - the return value for the Descriptions of the Numeric Specs&lt;br /&gt;
*mat SPos - the return value for the starting positions of the String Specs&lt;br /&gt;
*mat NPos - the return value for the starting positions of the Numeric Specs&lt;br /&gt;
&lt;br /&gt;
This function call would read the fields from the layout in filelay$, and it would return the prefix to prefix$. The Subs would be returned in mat SSubs$ and mat NSubs$.&lt;br /&gt;
&lt;br /&gt;
The Spec statements are returned in mat SSpec$ and mat NSpec$ and the Descriptions are returned in mat SDescription$ and mat NDescription$. The start positions on disk of each element are returned in mat SPos and mat NPos.&lt;br /&gt;
&lt;br /&gt;
All the arrays are optional. If you don’t pass them the information they are supposed to record is simply not returned.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutHeader ====&lt;br /&gt;
This function reads the header for a given file layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLayoutHeader(Layoutname$*255;&amp;amp;Filename$,Mat Keys$,Mat KeyDescription$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*LayoutName$ - Name of the layout to read&lt;br /&gt;
*Filename$ - The file name read from the layout&lt;br /&gt;
*Mat Keys$ - Array to be populated with the list of keys for the file&lt;br /&gt;
*Mat KeyDescription$ - Key Description String returned from the file&lt;br /&gt;
&lt;br /&gt;
==== fnReadEntireLayout ====&lt;br /&gt;
This function reads the entire layout by calling fnReadLayoutHeader and fnReadLayoutArrays.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadEntireLayout(Layoutname$*255;&amp;amp;Filename$,&amp;amp;Prefix$,Mat Keys$,Mat KeyDescription$,Mat Ssubs$,Mat Nsubs$,Mat Sspec$,Mat Nspec$,Mat Sdescription$,Mat Ndescription$,Mat Spos,Mat Npos)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*LayoutName$ - Name of the layout to read&lt;br /&gt;
*Filename$ - The file name read from the layout&lt;br /&gt;
*prefix$ - the return value for the prefix for the file&lt;br /&gt;
*Mat Keys$ - Array to be populated with the list of keys for the file&lt;br /&gt;
*Mat KeyDescription$ - Key Description String returned from the file&lt;br /&gt;
*mat SSubs$ - the return value for all the string subscripts in the layout&lt;br /&gt;
*mat NSubs$ - the return value for the numeric subscripts in the layout&lt;br /&gt;
*mat SSpec$ - the return value for the string fields specs&lt;br /&gt;
*mat NSpec$ - the return value for the numeric fields specs&lt;br /&gt;
*mat SDescription$ - the return value for the Descriptions of the String Specs&lt;br /&gt;
*mat NDescription$ - the return value for the Descriptions of the Numeric Specs&lt;br /&gt;
*mat SPos - the return value for the starting positions of the String Specs&lt;br /&gt;
*mat NPos - the return value for the starting positions of the Numeric Specs&lt;br /&gt;
&lt;br /&gt;
==== fnReadSubs ====&lt;br /&gt;
This function reads the subscripts from a layout into Subs arrays.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadSubs(Layout$,mat SSubs$,mat NSubs$,&amp;amp;Prefix$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - the file layout name&lt;br /&gt;
*mat SSubs$ - the String Subscript Names&lt;br /&gt;
*mat NSubs$ - the Number Subscript Names&lt;br /&gt;
*Prefix$ - the files Prefix&lt;br /&gt;
&lt;br /&gt;
==== fnReadKeyFiles ====&lt;br /&gt;
This function reads the list of key files from the layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadKeyFiles(Layout$,mat Keys$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*mat Keys$ - output array, the keys are returned here.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayouts ====&lt;br /&gt;
This function reads the file layout folder and returns all the applicable layouts in the passed in array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadLayouts(mat Dirlist$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Mat Dirlist$ - After running the function, mat Dirlist$ will contain a list of all the file layouts that FileIO can find.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutPath$ ====&lt;br /&gt;
This function doesn&#039;t actually interrogate your layouts. Instead, it interrogates your settings and returns the path specified for your layout files. This would usually be &amp;quot;filelay\&amp;quot; but you can change it in [[#fnSettings|fileio.ini.]]&lt;br /&gt;
&lt;br /&gt;
It has no parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let Path$=fnReadLayoutPath$&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnDoesLayoutExist ====&lt;br /&gt;
This function returns true if the given file layout exists. It returns false if the layout does not exist.&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;FnDoesLayoutExist(layout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - Layout to test for&lt;br /&gt;
&lt;br /&gt;
==== fnReadForm$ (uncompiled) ====&lt;br /&gt;
Sometimes you need to know the original form statement that fileio is using to read your data file, most often when you&#039;re debugging your file layout, and you&#039;re getting some problem when reading the file. The form statement that fileio normally returns is compiled using CFORM$ to save space in the array, and to make the execution of your read statements faster. You can use this function to return the original form statement for the file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let FormStatement$=fnReadForm$*10000(FileLayout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remember to dimension FormStatement to something huge! fnReadForm$ can return up to 10,000 characters.&lt;br /&gt;
&lt;br /&gt;
==== fnReadFormAndSubs ====&lt;br /&gt;
&lt;br /&gt;
This function does the same as above but it also reads the subscripts from the file into an array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let fnReadFormAndSubs(Layout$,mat Subs$,&amp;amp;ReadForm$,&amp;amp;StringSize,&amp;amp;NumberSize)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note that unlike most of our functions, all the above parameters are required.&lt;br /&gt;
&lt;br /&gt;
The layout is the layout you&#039;re interrogating. The Array will be populated with the subscripts after the function. The ReadForm$ variable will be filled with the form statement for the file. Remember to dimension it large enough. StringSize and NumberSize will contain the number of string fields and numeric fields in the file.&lt;br /&gt;
&lt;br /&gt;
Mat Subs$ will be returned, strings first, numbers last, matching the form statement that is returned. So Subs$(1) is the first string subscript and Subs$(StringSize+1) is the first Numeric subscript.&lt;br /&gt;
&lt;br /&gt;
=== Other Useful Functions (non-layout related) ===&lt;br /&gt;
&lt;br /&gt;
==== fnAskCombo ====&lt;br /&gt;
&lt;br /&gt;
Opens a window with a combo box and returns the users selection.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnAskCombo$*255(mat Description$;Caption$*60,Default$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Description$ - contains the combo box choices&lt;br /&gt;
*Caption$ - contains the optional caption for the window&lt;br /&gt;
*Default$ - the text of the item in mat Description$ that you want to be selected by default&lt;br /&gt;
&lt;br /&gt;
==== fnSendEmail ====&lt;br /&gt;
&lt;br /&gt;
This function sends an email and an optional attachment to the email address specified.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnSendEmail(Emailaddress$*255,Message$*10000;Subject$*255,Invoicefile$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*EmailAddress$ - the Destination Email Address&lt;br /&gt;
*Message$ - the Message$ to send&lt;br /&gt;
*Subject$ - the subject&lt;br /&gt;
*InvoiceFile$ - the filename of a file to attach. This is the BR filename (the function automatically converts it to an OS Filename.)&lt;br /&gt;
&lt;br /&gt;
The function returns 1 when the email was sent successfully, or 0 if it wasn&#039;t sent successfully.&lt;br /&gt;
&lt;br /&gt;
In order to use this function, you must have the emailcfg file layout in your layouts folder and you must have a copy of SendEmail.exe which is free and can be downloaded from the internet. Both of these files are included with the latest update of fileio.&lt;br /&gt;
&lt;br /&gt;
You also have to configure fileio with the authentication information for your email server.&lt;br /&gt;
&lt;br /&gt;
To configure your email server, simply run FileIO to get the data crawler, then select the emailcfg file layout and press F5 to edit it. Add a row if the file is empty.&lt;br /&gt;
&lt;br /&gt;
Simply fill in the information the file is asking for in the appropriate fields and save the data, and then test sending an email to make sure it worked.&lt;br /&gt;
&lt;br /&gt;
==== fnClientEnv$ ====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a Windows Environment Variable on the client under Client Server.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnClientEnv$*255(EnvKey$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*EnvKey$ is the name of the Windows Environment Variable to check on the client.&lt;br /&gt;
&lt;br /&gt;
The function returns the value of the entered environment variable.&lt;br /&gt;
&lt;br /&gt;
==== fnEmpty &amp;amp; fnEmptyS ====&lt;br /&gt;
These functions are for testing optional arrays that may or may not have been passed into your function. BR will give an error if your code attempts to use an optional array that wasn&#039;t passed in, so you can use these functions to test if the user actually passed in the optional array or not.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnEmpty(mat Numeric)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnEmptyS(mat String$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  def fnSomeFunction(String$,mat Array$; mat OptionalArray)&lt;br /&gt;
     if ~fnEmpty(mat OptionalArray) then&lt;br /&gt;
        ! mat Optional array was given, process it here.&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
==== fnReadScreenSize ====&lt;br /&gt;
This function reads the screen size of the given window (or window 0 if a window wasn&#039;t passed.) This is useful for centering a window on the screen, or for making sure window 0 is big enough for the child window you&#039;re trying to create.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadScreenSize(&amp;amp;Rows,&amp;amp;Cols;ParentWindow)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The screen size is returned in the first two parameters, and the third parameter tells the function which window to interrogate. If not given, it assumes window 0.&lt;br /&gt;
&lt;br /&gt;
==== fnBuildProcFile ====&lt;br /&gt;
This function builds a proc file to be executed later. This function and the next simplify the process of executing code in a proc file. It can even be used to spawn a new session of BR.&lt;br /&gt;
&lt;br /&gt;
To use it, call fnBuildProcFile one or more times and specify some lines of code to execute.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnBuildProcFile(Command$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;load Program2$&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;run&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;system&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  let fnRunProcFile(1)&lt;br /&gt;
&lt;br /&gt;
==== fnRunProcFile ====&lt;br /&gt;
&lt;br /&gt;
This function spawns a new copy of BR and in it, runs the proc file that you&#039;ve previously built using fnBuildProcFile (above).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; fnRunProcFile(;NoWait) &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The optional parameter &amp;quot;NoWait&amp;quot; causes the other session to spawn and run in a new thread. If you don&#039;t specify NoWait, the current session pauses and waits for the other session to close before proceeding.&lt;br /&gt;
&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;load Program2$&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;run&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;system&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  let fnRunProcFile(1)&lt;br /&gt;
&lt;br /&gt;
==== fnLog &amp;amp; fnErrLog ====&lt;br /&gt;
These next two functions are functions to aid in logging. When you call either of these two functions, you give them a string that you wish to log. They will open the FileIO Log File and add a record to the end of it containing some user information such as login_name and session$, and the string that you specified. FnErrLog does the same thing as fnLog except it also logs the Error Number and the Line.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnLog(string$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - the Log Message&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnErrLog(String$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - the Log Message&lt;br /&gt;
&lt;br /&gt;
==== fnLogArray ====&lt;br /&gt;
&lt;br /&gt;
This function logs the given arrays to the log file, logging each field in the arrays. Its useful for recording, for example, an entire data record that is about to be written to a data file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnLogarray(mat F$,mat f;Message$*512,CallingProgram$*255)&#039;&#039;&lt;br /&gt;
The first two parameters, of course, are the array to log. The third parameter is an optional message to be recorded along with the array, and the fourth optional parameter is the CallingProgram$ to save in the log along with the message. (The CallingProgram$ parameter can usually be passed as the system function Program$)&lt;br /&gt;
&lt;br /&gt;
==== fnSetLogChanges ====&lt;br /&gt;
This function works in conjunction with the next function, and they&#039;re for recording just what changed in a data file. When the file is read, you call fnSetLogChanges and record the &amp;quot;before&amp;quot; picture of the file record.&lt;br /&gt;
&lt;br /&gt;
After changes have been made and saved back to disk, you can call fnLogChanges below to record the actual changes.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnSetLogChanges(mat F$,mat F)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnLogChanges ====&lt;br /&gt;
This function is the other half of the function above. It compares the given arrays with the ones set previously in the above function and checks for changes. Then it generates a log message recording information about just the items that changed.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnLogChanges(mat F$,mat F;Message$*1024,CallingProgram$*255,Layout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You need to pass in the same two arrays as before, but this time the modified versions of them.&lt;br /&gt;
&lt;br /&gt;
You can also optionally pass a 1024 byte log message to record with the log entry.&lt;br /&gt;
&lt;br /&gt;
CallingProgram$ again should be passed as the system internal function Program$.&lt;br /&gt;
&lt;br /&gt;
The final parameter allows the passing of a Layout$. If you pass a Layout$, that layout is read and the subscripts are used when making the log message of changes, so that its easier to read. If you pass a layout, it will identify the changed fields by name. If you don&#039;t it will identify those fields by relative position number.&lt;br /&gt;
&lt;br /&gt;
==== fnViewLogFile ====&lt;br /&gt;
All of the above functions store the information by default into a BR internal file defined in the filelay\logfile layout.&lt;br /&gt;
&lt;br /&gt;
The fnViewLog function uses fnShowData to call the Data Crawler to display the FileIO Log File in a searchable listview.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnViewLogFile&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnReadLockedUsers ====&lt;br /&gt;
&lt;br /&gt;
This function returns a list of all users using the locked data file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLockedUsers(mat Users$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Users$ - the list of users is returned here&lt;br /&gt;
&lt;br /&gt;
==== fnDisplayLength ====&lt;br /&gt;
This function calculates the display length of a field based on its form spec.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDisplayLength(Spec$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Spec - the Form Spec to return the display length of.&lt;br /&gt;
&lt;br /&gt;
==== fnLength ====&lt;br /&gt;
This function calculates the length on disk of a field based on its form spec.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnLength(Spec$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Spec$ - the Form Spec to return the display length of.&lt;br /&gt;
&lt;br /&gt;
== FileIO fnSettings (Global Settings Code) ==&lt;br /&gt;
&lt;br /&gt;
The FileIO library can be made to implement certain policies across the board.  These are established by creating a file called fileio.ini and typing statements like the following into it. This file is &amp;quot;PROCed&amp;quot;, so you don&#039;t want to put line numbers in it.&lt;br /&gt;
&lt;br /&gt;
Anything you don&#039;t specify in fileio.ini will take its default value, shown below. So you only need to specify the items that you want to be different.&lt;br /&gt;
&lt;br /&gt;
Note, for the boolean settings below, 1 denotes TRUE and 0 denotes FALSE.&lt;br /&gt;
&lt;br /&gt;
  let EnforceDupkeys=1                   ! Enforce that key number 1 is unique key&lt;br /&gt;
  let Defaultfilelayoutpath$=&amp;quot;filelay\&amp;quot;  ! Path To Your File Layouts&lt;br /&gt;
  let Promptonfilecreate=1               ! Ask User Before Creating New Files&lt;br /&gt;
  let Createlogfile=0                    ! Use Logging&lt;br /&gt;
  let StartFileNumber=1                  ! Set above 300 to avoid conflicts with legacy programs.&lt;br /&gt;
  let CheckIndex=0                       ! Automatically Verify Indexes (slow)&lt;br /&gt;
  let CompressColumns=0                  ! Shrink or Expand Columns in Data Crawler by Default&lt;br /&gt;
  let MaxColWidth=20                     ! Max Default Column Width in Data Crawler&lt;br /&gt;
  let LogLibrary$=&amp;quot;&amp;quot;                     ! Defaut Log Library, defaults to None&lt;br /&gt;
  let LogLayout$=&amp;quot;&amp;quot;                      ! Log file layout, defaults to Internal File&lt;br /&gt;
  let AnimateDatacrawler=1               ! Use ScreenIO Animation for Datacrawler&lt;br /&gt;
  let TemplatePath$=&amp;quot;filelay\template\&amp;quot;  ! Default Template Path&lt;br /&gt;
  let IgnoreLayouts$=&amp;quot;&amp;quot;                  ! List any Ignore Layouts here.&lt;br /&gt;
  let CloseFileSimple=0                  ! Use simple comparison for fnCloseFile&lt;br /&gt;
&lt;br /&gt;
==== EnforceDupkeys ====&lt;br /&gt;
&lt;br /&gt;
Turn on the EnforceDupkeys option to force that the first key listed in your file layouts is a unique key. FileIO will generate the standard BR error for Dupkeys when attempting to create indexes if it is not unique.&lt;br /&gt;
&lt;br /&gt;
==== DefaultFileLayoutPath$ ====&lt;br /&gt;
&lt;br /&gt;
Use the DefaultFileLayoutPath option to specify the path from your programs to your file layout folder. The default is &amp;quot;filelay\&amp;quot;. Use this setting if you want to place your file layouts in another folder from the default.&lt;br /&gt;
&lt;br /&gt;
==== PromptOnFileCreate ====&lt;br /&gt;
&lt;br /&gt;
Use the PromptOnFileCreate setting to cause FileIO to display a message box whenever it is attempting to create a new file. This happens during the automatic update procedure, as well as during any attempt to access a file that does not exist. This setting should be turned off in your live system, and only turned on for development purposes. If you use the message box to cancel creating of the new file, then the file is not created, and fileIO or your application will most likely give an error when you attempt to actually access the new file.&lt;br /&gt;
&lt;br /&gt;
It can be useful during development to make sure that you don&#039;t accidentally create the wrong files, due to an incorrectly specified path or a typeo in the filename in the layout file. However, in a live system, these things have already been tested, and you generally want the default behavior, because you don&#039;t want your users to have the ability to cancel the normal operation of FileIO.&lt;br /&gt;
&lt;br /&gt;
==== CreateLogFile ====&lt;br /&gt;
&lt;br /&gt;
Use this option to specify weather or not to use the FileIO log file. If it is turned on, a log file called FileIO.log in the current directory is created with entries listing all attempts to open a file, automatically update one, or automatically update your indexes.&lt;br /&gt;
&lt;br /&gt;
==== StartFileNumber ====&lt;br /&gt;
&lt;br /&gt;
Use this option to set the starting file number that the fnGetFileNumber and the fnOpen functions use to search for available file numbers. This is so that if you have certian reserved file numbers in your code, you can make sure that FileIO will not use those reserved file numbers, causing a conflict with your already existing programs. The default is 1, which is fine if your software does not have any reserved file numbers.&lt;br /&gt;
&lt;br /&gt;
The allowable BR file numbers are 1-200 and 300-999.&lt;br /&gt;
&lt;br /&gt;
==== CheckIndex ====&lt;br /&gt;
&lt;br /&gt;
This function is used for Partial FileIO Implementations. If all of your software uses FileIO then all of your indexes are kept automatically up to date by the FileIO library and BR&#039;s internal file processing systems. However, if some of your programs do not use FileIO, and you use the FileIO library to add a new index file that those other programs do not know about, then its possible for the additional index file to become out of date when the master file is updated by your other programs.&lt;br /&gt;
&lt;br /&gt;
Use this setting to cause FileIO to check the DateTime stamp on all your index files when opening a new file, and automatically update any indexes that may have potentially gotten out of date from other programs.&lt;br /&gt;
&lt;br /&gt;
This option slows down the processing of the fnOpen function, particularly when running under client server over the internet. If you know that every program in your application suite uses FileIO, and that any programs that do not use FileIO still properly update all the indexes that your data file uses, then you can safely leave this setting turned off, and optimize your performance when opening several files using the fileIO system.&lt;br /&gt;
&lt;br /&gt;
==== CompressColumns ====&lt;br /&gt;
This instructs the datacrawler to use smaller widths for small columns. If CompressColumns is false, the data crawler will make the column the width of the field or the width of the caption, whichever is wider. If CompressColumns is true, it will use the width of the field, not the caption.&lt;br /&gt;
&lt;br /&gt;
==== MaxColWidth ====&lt;br /&gt;
This limits the column width to a set amount. This is applied after CompressColumns above.&lt;br /&gt;
&lt;br /&gt;
==== LogLibrary$ ====&lt;br /&gt;
If a library is specified here, then fileio looks for a BR library with the specified name, and attempts to call a library function in it called fnFileIOLog that. This function should expect six parameters, which are Logstring$, Login_Name$, Session$, Days of Date$, Time$, and CallingProgram$, if LogLayout is also nonblank.&lt;br /&gt;
&lt;br /&gt;
If you specify a LogLibrary and LogLayout is blank, then it calls your function giving it only 1 parameter.&lt;br /&gt;
&lt;br /&gt;
It will call your function &#039;&#039;&#039;&#039;&#039;instead of&#039;&#039;&#039;&#039;&#039; the normal log file. Use this to implement your own logging functions however you want.&lt;br /&gt;
&lt;br /&gt;
==== LogLayout$ ====&lt;br /&gt;
Use this setting to specify an alternate file layout for an alternate file to do the logging in. Base the file layout for this file on the logfile we supply for you in the filelay folder. It should have at least those fields, which our log routine will automatically populate, but you can add other fields if you want (though you will need to manage them yourself).&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t specify LogLayout, the default filelay\logfile will be used. This will allow you to also use the fnViewLogFile function to access it.&lt;br /&gt;
&lt;br /&gt;
==== AnimateDataCrawler ====&lt;br /&gt;
The sister library [[ScreenIO]] has a feature that allows you to use an animation of a clock in your loading screens in your own programs. If you have [[ScreenIO]] then FileIO will automatically detect it and use it to display a loading animation while the data in the data crawler loads.&lt;br /&gt;
&lt;br /&gt;
Set AnimateDataCrawler to false (0) in your fileio.ini file to bypass the animations if you do have screenio but don&#039;t want to see the animations anyway.&lt;br /&gt;
&lt;br /&gt;
==== TemplatePath$ ====&lt;br /&gt;
This setting points to the folder that contains the code templates used by the Generate Code button on the main page of the Data Crawler.&lt;br /&gt;
&lt;br /&gt;
==== IgnoreLayouts$ ====&lt;br /&gt;
This is a comma delimited list of all layouts that you wish to suppress from appearing on the main page of the data crawler. You can still access these layouts with your code, but they won&#039;t be listed in the data crawler for you to access.&lt;br /&gt;
&lt;br /&gt;
Whatever you&#039;re using for a log layout, is automatically added to this list.&lt;br /&gt;
==== CloseFileSimple ====&lt;br /&gt;
The fnCloseFile function closes all the individual handles to a data file that was opened for output using multiple keys.&lt;br /&gt;
&lt;br /&gt;
For BR 4.18 and higher, we support a better algorithm for detecting which files are matches for a given opened file number.&lt;br /&gt;
&lt;br /&gt;
Set CloseFileSimple to true (1) to force it to check the old way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== FileIO Add-on Packages ==&lt;br /&gt;
&lt;br /&gt;
Many FileIO Add-on packages are currently in the works.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Library ===&lt;br /&gt;
&lt;br /&gt;
The [[ScreenIO Library]] is a sister library to the FileIO library. The ScreenIO library requires the FileIO library in order to run.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO library is a complete Rapid Application Design tool that enables you to implement custom screen functions anywhere in your exiting programs.&lt;br /&gt;
&lt;br /&gt;
If you call the ScreenIO Library as a function library, you call a function called fnFM and tell it which screen you wish to use. The ScreenIO library loads your user interface, loads your data files, and preforms all the file maintenance operations you have designed into your screens.&lt;br /&gt;
&lt;br /&gt;
You can find out the latest information about the ScreenIO library in the ScreenIO page.&lt;br /&gt;
&lt;br /&gt;
=== Audit BR ===&lt;br /&gt;
&lt;br /&gt;
The [[AuditBR|Audit BR]] developer tool makes a backup copy of your file layouts. Then you run some code you&#039;re trying to test, and finally, run Audit BR again, to get a report showing all the changes to any of your data files automatically.&lt;br /&gt;
&lt;br /&gt;
== What’s New (also described above) ==&lt;br /&gt;
=== 2018 ===&lt;br /&gt;
*Support for dates in any storage formats on disk (v2.48)&lt;br /&gt;
&lt;br /&gt;
=== 2015 ===&lt;br /&gt;
*Added Rec to display for fnShowData&lt;br /&gt;
*Added FormStatement$ for debugging of form statements inside fileio&lt;br /&gt;
*Added mat BadRead$ for debugging of 726 errors when making new layouts&lt;br /&gt;
*Fixed a bug causing crash when logging things from long program folders&lt;br /&gt;
*fnClientEnv$ - reads a Windows Environment variable on the client using the command shell&lt;br /&gt;
*fnAskCombo$ - added an optional parameter to set default selection.&lt;br /&gt;
&lt;br /&gt;
=== 2010 - 2014 ===&lt;br /&gt;
*FileIO now caches your file layouts in memory to make it much faster then before when opening the same data file in multiple programs.&lt;br /&gt;
*Generate Layout Wizard&lt;br /&gt;
*fnShowData&lt;br /&gt;
*Improved Logging&lt;br /&gt;
*fnViewLogFile&lt;br /&gt;
*Import/Export&lt;br /&gt;
*Import/Export by Function&lt;br /&gt;
*Many other speed increases&lt;br /&gt;
*if ScreenIO is present, Datacrawler uses the animation routines&lt;br /&gt;
*fnBuildProcFile &amp;amp; fnRunProcFile&lt;br /&gt;
*fnGenerateLayout &amp;amp; fnWriteLayout&lt;br /&gt;
*fnReadForm$&lt;br /&gt;
*fnReadFormAndSubs&lt;br /&gt;
*fnGetFileDateTime$&lt;br /&gt;
*fnReadLayoutPath$&lt;br /&gt;
*fnSortKeys&lt;br /&gt;
*fnSetLogChanges&lt;br /&gt;
*fnLogChanges&lt;br /&gt;
*fnLogArray&lt;br /&gt;
*fnReadScreenSize&lt;br /&gt;
*fnEmpty&lt;br /&gt;
*fnEmptyS&lt;br /&gt;
*Many other useful functions that were added to the documentation at earlier dates.&lt;br /&gt;
&lt;br /&gt;
=== Spring 2009 ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;New Functions:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The FileIO Library has been updated in Spring 2009 to provide several new functions:&lt;br /&gt;
&lt;br /&gt;
*fnReadRecordWhere&lt;br /&gt;
*fnKey$&lt;br /&gt;
*fnBuildKey$&lt;br /&gt;
*fnReadUnopenedDescription$&lt;br /&gt;
*fnUpdateFile&lt;br /&gt;
*fnDisplayLength&lt;br /&gt;
*fnLength&lt;br /&gt;
*fnReadLayoutHeader&lt;br /&gt;
*fnReadEntireLayout&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Speed Increases:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Thanks to the BR [[Profiler]], we have increased the speed of FileIO fnOpen function by ten times when running over a LAN and by 100 times when running over the internet using Client Server.&lt;br /&gt;
&lt;br /&gt;
In order to get the new Speed Upgrades, you will need to make sure that you use the latest copy of the [[#fnOpen_Function|fnOpen]] function in each one of your programs that use FileIO.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Network FileIO:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
This version of FileIO has been optimized to work better in network situations.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;FnSettings: &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
There are more configuration options in the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] routine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Automatic Update Speed Fix:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The automatic update proceedure has been made to run more then 100 times faster then before according to our benchmarking tests.&lt;br /&gt;
&lt;br /&gt;
=== Fall 2008 ===&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;DataCrawler Grid:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
By popular request we added a read/write version to the data crawler. This version works exactly the same as the datacrawler did before but it displays all the contents of your data files in a grid instead of a listview. &lt;br /&gt;
&lt;br /&gt;
When you run the fileIO library as a program, it launches a tool known as the [[#DataCrawler|DataCrawler]]. The DataCrawler shows a listview displaying all your layout files in it. If you select one, it builds another listview with all the data in your selected data file.&lt;br /&gt;
&lt;br /&gt;
If you are looking at the first list of all your file layouts, and you press F5, a grid will be build displaying all the data in your data files. You can change any of the records you like, and when you&#039;re done, your changes will be saved to the data file. Additionally, you can Add or Delete records using the buttons at the bottom. Any changes you make are not written to the disk until you click the &amp;quot;Save&amp;quot; button. If you press ESC (Cancel) the grid is closed and all changes you made sinse the last save are lost.&lt;br /&gt;
&lt;br /&gt;
This tool is for programmers only. Do not give your end users access to the DataCrawler.&lt;br /&gt;
&lt;br /&gt;
Use the DataCrawler at your own risk. Gabriel Bakker and Sage AX are not responsible for any harm that comes to your data files through the use of this or any other tools we offer.&lt;br /&gt;
&lt;br /&gt;
The DataCrawler is not designed to be used to maintain your data files. It can be used carefully to correct small things in your data files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Support for Nonstandard Paths:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Many BR Vendors keep different versions of the same data files in different locations. For example, sometimes a BR vendor will use a different Data folder to represent data for different Warehouses, or Customers. In cases like this it is necessary for your programs to specify the path to your data files. They may do so by specifying the optional &amp;quot;PATH&amp;quot; parameter to your data files. See the section [[#fnOpenFile]] for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Support for Nonstandard Layout Files Path:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Old versions of the fileIO library required you to place all your file layouts in a subfolder of your program directory called &amp;quot;filelay&amp;quot;. We have now changed the Fileio library to allow you to place your file layouts any place you want. The only requirement is that they are all together in one folder by themselves.&lt;br /&gt;
&lt;br /&gt;
If you use a nonstandard path in the fileIO library, it is necessary to make a change to the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] code in your copy of fileio.br.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Prompt on Create:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The FileIO library automatically creates any data files that it can&#039;t find. This was done to make it easier to deploy your finished programs - if you had any empty data files you could omit them from the packages and they would be created when they were needed, on the fly.&lt;br /&gt;
&lt;br /&gt;
The current version of the FileIO library contains the same ability. However, it prompts you before creating any data files. This helps to avoid bugs that happen from incorrectly specifying the path to your data files.&lt;br /&gt;
&lt;br /&gt;
However, if you do intend for your data files to be autocreated, then you probably don&#039;t want your end users to modify them. Therefore, you can use the PromptOnCreate setting in the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] code to specify. If this value is set to true, then the fileIO library will prompt you whenever it attempts to Autocreate a data file. If it is set to false, then the fileIO library will create the data files without prompting you, like it always did before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;fnSettings:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The newest version of the FileIO library supports some features that require you to specify Global Settings values. These are done by modifying the contents of the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] routine at the beginning of the fileIO library.&lt;br /&gt;
&lt;br /&gt;
=== Fall 2006 ===&lt;br /&gt;
Many improvements have been made in the FileIO library over the summer. This section is intended to acquaint you with the highlights of those changes. Most of these improvements were built from ideas generated during the discussion at the April conference.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Intermixed String and Numeric Specs:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The File Library has been expanded to allow the reading of data files that contain mixed string and numeric specs. This is to aid those of you who are planning on implementing the FileIO Library on existing data files which may not be organized with strings first and numbers second.&lt;br /&gt;
&lt;br /&gt;
The central idea of the FileIO Library is based upon the reading of your data files into a String and Numeric array. This will enable you to refer to the fields in your file by using a named subscript, saying F$(FM_NAME) to refer, for example, to the farm file’s name field. The advantage to this is that when you change the file layout, all your existing programs will not have to be modified, because they will only be looking at F$(FM_NAME). If the name field changes from the third string field to the fourth, the value of FM_NAME will also change, and you won’t have to worry about updating your data files.&lt;br /&gt;
&lt;br /&gt;
However, in order to support the reading of a data file with intermixed string and numeric specs, the generated form statement will actually calculate the position of any fields that are not in order, so that the file read statement will still return all string fields first (into your string array) and the numeric fields second (into your numeric array). You do not need to worry about this; the library does it for you. All you have to do is read your file and use the data values.&lt;br /&gt;
&lt;br /&gt;
The only thing that is required is making sure that all your string subscript names end with a “$”. This will tell the library that they are strings. Thank you, George, for this suggestion.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Versioning / Automatic Updates:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The file layouts have been expanded to contain a version number. This version number will be used to determine when a file needs to be updated. The version number is the third parameter in the file layout.&lt;br /&gt;
&lt;br /&gt;
Any time you wish to change your file layouts, simply increment this version number. Each time the library attempts to open a data file, the file’s version is checked and compared with the version in the file layout. If the file layout has been changed (if the version in the file layout is greater then the version in the file) then the file will be updated to the latest version. Depending on the file size this may take a couple of moments. A simple progress bar will be displayed on screen while this is happening. The progress bar will be displayed in its own window, so it should not affect anything your programs may have had on screen.&lt;br /&gt;
&lt;br /&gt;
The library uses the following procedure for updating a file. First, the file is copied to a backup file (prefixed by the letter ‘o’ for old). So color.dat would become ocolor.dat, and color.key would become ocolor.key. Then the new file is created and marked with the proper version number. (color.dat, color.key). The old file is opened in read-only mode, and the new file is opened for OutIn. The update routine actually reads through the old file layout, and one record at a time creates a new record, using the new file layout, with the same data, saving it to the new data file.&lt;br /&gt;
&lt;br /&gt;
When it is done upgrading, the progress bar window is closed, and the file is reopened in the fashion you described in your call to fnOpen, and flow returns to your program as though nothing unusual has happened.&lt;br /&gt;
&lt;br /&gt;
If an error occurs during processing, the routine will do what it can to roll your data files back to the previous version, but please make frequent backups of your data files anyway, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Error Checking – If there is a mistake in the file layout:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The routine attempts to discover the cause of the error in the case that one is encountered due to a missing file, a file sharing violation, or an invalid or corrupt file layout. If this should happen, the program is paused, and a text message is printed out explaining the most likely source for the error, including what part of the file layout, if any, may have caused the error.&lt;br /&gt;
&lt;br /&gt;
You may then examine the printed text, and the contents of the BR system variables ERR and LINE to determine the problem. If you type “GO”, the next line will be execute “system”, ending your program.&lt;br /&gt;
&lt;br /&gt;
If the file was in the middle of an upgrade when the error happened, it will be automatically rolled back to the previous version, so that when you fix the problem and try to run your program again, the file will again attempt to update from the beginning, and you won’t have to worry about corrupted data.&lt;br /&gt;
&lt;br /&gt;
However, please backup your data before upgrading your data files anyway, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Implementation of Keys / Creation of New Data Files:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The library has been expanded to automatically create all new data files, and to automatically update any existing files. This means that in the file layout header, two new fields that were previously ignored are no longer ignored. The RECL value that you specify in your file layout will be used, along with the description/definition of your keys file. When you open a new file (or update an existing one), the library will calculate the proper kps and kln by evaluating the key description. This key description must match up with subscript values from the data elements in your file, and more then one may be specified, but they must be separated with slashes (/). If I wanted my Farm File to be keyed based on CODE and NAME, the proper key description would be:&lt;br /&gt;
&lt;br /&gt;
  farm.key, CODE/NAME&lt;br /&gt;
&lt;br /&gt;
The library will then look up the position and length on disk of the CODE and NAME fields and put them together to create the proper keys during an update or creation of a new file. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;DataCrawler:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
Perhaps the most exciting new addition to the library is the addition of a programming tool I like to call a DataCrawler. If you run the FileIO Library directly as a program, instead of using it as a library, it will function as a DataCrawler. The DataCrawler requires a New Gui version of BR, as it requires a ListView to be able to properly and easily display the data in your files.&lt;br /&gt;
&lt;br /&gt;
If you run it in an older version of BR you will get a message, telling you to run it in a newer copy. If you run it in a New Gui version of BR with CONFIG GUI OFF, then GUI will be turned temporarily on for the use of the DataCrawler and then turned off again when you are finished. If you run it in a New Gui version of BR with GUI ON, it will just run normally.&lt;br /&gt;
&lt;br /&gt;
When you run the DataCrawler, first you will see a ListView displaying every file layout it can find in the filelay folder. If you select a file, the DataCrawler will open a large ListView with as many columns as there are fields in the file. The Column Headings will come from the element descriptions in your data files, and the column widths will come from the displayed width of the fields. There will be a row for every record in your data file, and you can resize the column widths, and scroll around the data file to view the raw data of your BR data files on disk.&lt;br /&gt;
&lt;br /&gt;
If you are dealing with a particularly enormous data file (50,000+ records) it can take a moment to populate the ListView with the data in your data file. You may hit ESC to stop loading if you like, and view only the already loaded records.&lt;br /&gt;
&lt;br /&gt;
If you would like to look up a particular record (based only upon the primary key for the data file), you may press F4. This will give you a window which asks you to input the key or partial key. When you press enter, the file will be reloaded, starting at the key you specified and continuing on to the end of the file, or until you press ESC. The records you are looking for should appear at the top of the ListView.&lt;br /&gt;
&lt;br /&gt;
To reset the ListView and look at the contents of the entire file again, simply press F4, and enter a blank (“”) key.&lt;br /&gt;
&lt;br /&gt;
Finally, as with any ListView, you may resort your data by clicking on any of the column headings. Then you can use the slider bar at the right to scroll down to the record you desire.&lt;br /&gt;
&lt;br /&gt;
This is a programming tool and is not designed to be used by an end user. This tool will open your file in read-only mode. It will not allow you to modify the data; I leave that as an exercise for the reader. However, it will update any datafiles you view to the latest version (if they need to be updated) when it opens them, just as any other program that uses the library will do.&lt;br /&gt;
&lt;br /&gt;
== Appendix (Examples)==&lt;br /&gt;
&lt;br /&gt;
=== Example.br ===&lt;br /&gt;
  00010    ! example.br - This program is an example of for the data reading simplification&lt;br /&gt;
  00020    ! Copyright April 2006 by Gabriel Bakker&lt;br /&gt;
  00030    ! Distributed open source as a Christmas gift to brag members&lt;br /&gt;
  00040    !&lt;br /&gt;
  00100    execute &amp;quot;config gui off&amp;quot;&lt;br /&gt;
  01020    DIM form$(1)*255&lt;br /&gt;
  01030    DIM color$(1)*255,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*255,colorcat(1)&lt;br /&gt;
  02020    library &amp;quot;fileio&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
  04000 !&lt;br /&gt;
  04010 Openfiles: ! Open your files here&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
  06000    ! gosub WriteFiles ! If you want to test this line, make sure to drop flag from 4030&lt;br /&gt;
  07000 !&lt;br /&gt;
  07010 MainBit: ! This&#039;un here&#039;s tha Main Bit&lt;br /&gt;
  07030    RESTORE #ColorFile:&lt;br /&gt;
  07100    ReadNextcolor: ! Read next record&lt;br /&gt;
  07120       read #ColorFile, using form$(ColorFile) : mat Color$, mat Color eof EndReadColor&lt;br /&gt;
  07180       PRINT Color$(co_name)&amp;amp;&amp;quot; (&amp;quot;&amp;amp;Color$(co_html)&amp;amp;&amp;quot;) is a member of the &#039;&amp;quot;;&lt;br /&gt;
  07190       PRINT trim$(fnReadDescription$(ColorcatFile,cc_Name,Color$(co_category),mat Colorcat$,mat Colorcat,mat form$))&amp;amp;&amp;quot;&#039; category.&amp;quot;&lt;br /&gt;
  07290       goto ReadNextColor&lt;br /&gt;
  07300    EndReadcolor: ! Finished with Color File&lt;br /&gt;
  08000    STOP&lt;br /&gt;
  25000 !&lt;br /&gt;
  25010 WriteFiles: ! Uncalled routine to demonstrate writing files&lt;br /&gt;
  25105       let color$(co_code)=&amp;quot;GD&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Gold&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;FFD700&amp;quot;&lt;br /&gt;
  25110       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25115       let color$(co_code)=&amp;quot;LV&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Lavender&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;BL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;E6E6FA&amp;quot;&lt;br /&gt;
  25120       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25125       let color$(co_Code)=&amp;quot;OR&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Orange&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;FFA500&amp;quot;&lt;br /&gt;
  25130       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25205       let colorcat$(cc_Code)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_Name)=&amp;quot;Yellows&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_html)=&amp;quot;FFFF00&amp;quot;&lt;br /&gt;
  25210       write #colorcatfile, using form$(colorcatfile): mat colorcat$,mat colorcat&lt;br /&gt;
  25215       let colorcat$(cc_Code)=&amp;quot;BL&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_Name)=&amp;quot;Blues&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_html)=&amp;quot;0000FF&amp;quot;&lt;br /&gt;
  25220       write #colorcatfile, using form$(colorcatfile): mat colorcat$,mat colorcat&lt;br /&gt;
  25300    return&lt;br /&gt;
  40000 !&lt;br /&gt;
  40010 Open: ! ***** Function to call library openfile and proc subs&lt;br /&gt;
  40020    def fnOpen(FILENAME$, MAT F$, MAT F, MAT FORM$;INPUTONLY,KEYNUM,___,INDEX)&lt;br /&gt;
  40025       dim _FileIOSubs$(1)*50&lt;br /&gt;
  40030       let fnopen=fnopenfile(FILENAME$, MAT F$, MAT F, MAT FORM$,INPUTONLY,KEYNUM,MAT _FileIOSubs$)&lt;br /&gt;
  40040       for Index=1 to udim(mat _FileIOSubs$) : execute (_FileIOSubs$(Index)) : next Index&lt;br /&gt;
  40090    fnend&lt;br /&gt;
  50000 !&lt;br /&gt;
  60000 Ignore: Continue&lt;br /&gt;
  &lt;br /&gt;
  Color File Layout&lt;br /&gt;
  color.dat, CO_, 1&lt;br /&gt;
  color.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Color Code,                  C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  CATEGORY$,      General Category of Color,   C    6&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
&lt;br /&gt;
  ColorCat File Layout&lt;br /&gt;
  colorcat.dat, CC_, 0&lt;br /&gt;
  colorcat.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Category Code,               C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
  &lt;br /&gt;
Example Layout showing multiple keys (price)&lt;br /&gt;
  price.dat, PR_, 0&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  X,              Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=FileIO_Library&amp;diff=10964</id>
		<title>FileIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=FileIO_Library&amp;diff=10964"/>
		<updated>2018-09-18T16:04:46Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* What’s New (also described above) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;FileIO&#039;&#039;&#039; Library began as a project to find a way to reduce the headache associated with making changes to data files. In my experiences working for [[BRC]], I had to make a change to the commun file, a data file that stores information about communication with EDI VANs. I added some new fields, and removed a couple of old fields, and then I began searching through the BRC program suite to find and modify each program that referenced this data file in order to update it with the proper new form statement. This task quickly became daunting as I noticed that out of BRC’s program suite of over 600 programs, more than one third of them referenced the commun file. With 223 programs to modify, the task was given up as hopeless and tabled indefinitely.&lt;br /&gt;
&lt;br /&gt;
I am happy to announce that we have solved this problem. When I have to make a change to a data file layout for my customers today, I can complete the task in under 1 minute, and not a single program needs to be changed in order to continue working with the new file layout. In fact, I don’t even have to update my customer’s data files, as the FileIO library takes care of this for me as well.&lt;br /&gt;
&lt;br /&gt;
The trick is to define your file layouts in an ASCII text file layout file that I will tell you about in a minute. The FileIO Library will actually parse through your file layouts, and it will instruct your programs how to read the data file, so that you don’t have to. It will also automatically detect when you make changes to the file layout, and it will update your customer’s data files on the fly to make sure they have the latest version. Finally, it even contains a DataCrawler that you can use to examine the contents of any of your BR data files in a raw format.&lt;br /&gt;
&lt;br /&gt;
For more information about the FileIO Library visit the [http://www.sageax.com/products/fileio-library/ Sage AX Website]&lt;br /&gt;
&lt;br /&gt;
To download the latest copy of FileIO, click [http://www.sageax.com/downloads/FileIO.zip here.]&lt;br /&gt;
&lt;br /&gt;
== Method of Operation ==&lt;br /&gt;
The file IO library parses a formatted text file layout and uses this information to structure the opening and initializing of the reading of a file “object”. The word object here is used to refer to all the data in a given record layout in one of your files. This library is easy to use, and provided you follow some simple standards, it will simplify your life immensely.&lt;br /&gt;
&lt;br /&gt;
You will need to define one array for all forms and add a snippet of code (given below) to the program for interfacing with with the library. For each file you will need to define a couple of arrays and use the library to open them. From that point on access to data is simple and direct. &lt;br /&gt;
&lt;br /&gt;
=== File Object Arrays ===&lt;br /&gt;
&lt;br /&gt;
First, in your program you must create two arrays to store the file information. If we are dealing with the Color File these would be MAT COLOR$ and MAT COLOR. One will store all the string information about a color, and the other will store all the numeric data. Our working example will involve two files: a Color File and a Color Category File. You should dimension these to:&lt;br /&gt;
&lt;br /&gt;
  01030    DIM color$(1)*1000,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*1000,colorcat(1)&lt;br /&gt;
&lt;br /&gt;
We&#039;re dimensioning the string arrays to 1000. This is the length of one field in the color file. It needs to be at least as big as the largest string field in the data file.&lt;br /&gt;
&lt;br /&gt;
However, it is recommended to make sure the length is long enough to handle any field you might eventually add to the file at any point in the future. BR supports multi-line textboxes, so I sometimes add long memo fields to my data files that might be 400 or 800 or even 1000 characters long, therefore 1000 is the length I use now in all my new development.&lt;br /&gt;
&lt;br /&gt;
But anything will work as long as its long enough to handle the largest data field in your file.&lt;br /&gt;
&lt;br /&gt;
=== Forms Array ===&lt;br /&gt;
&lt;br /&gt;
You will also need a variable to store the form statement associated with reading the files. This form statement will be dynamically generated whenever a new file is opened. It will say: &lt;br /&gt;
&lt;br /&gt;
  01020    DIM form$(1)*255&lt;br /&gt;
&lt;br /&gt;
This form statement will be compiled by the FileIO open statement and BR limits all form statements to 255 bytes compiled anyway, so 255 is enough for the Forms$ array.&lt;br /&gt;
&lt;br /&gt;
=== Library Linkage ===&lt;br /&gt;
&lt;br /&gt;
You will also need the library statement:&lt;br /&gt;
&lt;br /&gt;
  02020 library &amp;quot;fileio.br&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
&lt;br /&gt;
=== fnOpen Function ===&lt;br /&gt;
&lt;br /&gt;
Now, add a snippet of code to interface with the library.&lt;br /&gt;
&lt;br /&gt;
Because BR libraries do not share variables with the programs they are called from, we will need to execute a proc file whenever we open a file to set the names of all our variables after we return. Add the following snippet of code into your program. It will create an FnOpen function that calls the library version and runs the proc file. The $$$ at the end of the procfile name tells the procfile to self-destruct after execution. Since this procfile is used simply to return variable information back from the library to the main program, we don’t need it sitting around collecting dust.&lt;br /&gt;
&lt;br /&gt;
  99010 OPEN: ! ***** Function To Call Library Openfile And Proc Subs&lt;br /&gt;
  99020    def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths,Supress_Prompt,Ignore_Errors,Suppress_Log,___,Index)&lt;br /&gt;
  99030       dim _FileIOSubs$(1)*800, _Loadedsubs$(1)*80&lt;br /&gt;
  99040       let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$, Supress_Prompt,Ignore_Errors,Program$,Suppress_Log)&lt;br /&gt;
  99050       if Srch(_Loadedsubs$,Uprc$(Filename$))&amp;lt;=0 then : mat _Loadedsubs$(Udim(_Loadedsubs$)+1) : let _Loadedsubs$(Udim(_Loadedsubs$))=Uprc$(Filename$) : for Index=1 to Udim(Mat _Fileiosubs$) : execute (_Fileiosubs$(Index)) : next Index&lt;br /&gt;
  99060    fnend&lt;br /&gt;
&lt;br /&gt;
Or, for those with [[Lexi]]:&lt;br /&gt;
  OPEN: ! ***** Function To Call Library Openfile And Proc Subs&lt;br /&gt;
     def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths,Supress_Prompt,Ignore_Errors,Suppress_Log,___,Index)&lt;br /&gt;
        dim _FileIOSubs$(1)*800, _Loadedsubs$(1)*80&lt;br /&gt;
        let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$, Supress_Prompt,Ignore_Errors,Program$,Suppress_Log)&lt;br /&gt;
        if Srch(_Loadedsubs$,Uprc$(Filename$))&amp;lt;=0 then : mat _Loadedsubs$(Udim(_Loadedsubs$)+1) : let _Loadedsubs$(Udim(_Loadedsubs$))=Uprc$(Filename$) : for Index=1 to Udim(Mat _Fileiosubs$) : execute (_Fileiosubs$(Index)) : next Index&lt;br /&gt;
     fnend&lt;br /&gt;
&lt;br /&gt;
=== Using FileIO in Your Programs ===&lt;br /&gt;
Now you are ready to process files. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;You simply open the files by saying:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;read each file as follows:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  30120    read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore  &lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;and access the data:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  30180    LET ColorCode$=color$(co_Code) !:&lt;br /&gt;
           LET ColorName$=color$(co_Name)&lt;br /&gt;
&lt;br /&gt;
=== How it Works ===&lt;br /&gt;
These statements tell the File Library to look in the filelay folder to find the file layout for the Color File, and read it to find out what the Color File looks like. Then Open the Color File, and set MAT COLOR$ and MAT COLOR to the correct number of elements to hold an entire color record. Finally, it will define several variables that we can use as pointers into (subscripts) these arrays to access the data we after reading it, and it will place the file handle into a variable called colorfile.&lt;br /&gt;
&lt;br /&gt;
The second open above will do the same thing to the color category file, except the 1 parameter tells the function to open readonly. The subscripts array will be executed, creating the subscripts in memory, and the pointers (subscripts) will be set in the calling program. So, if I had a file layout such as the following:&lt;br /&gt;
&lt;br /&gt;
  color.dat, CO_, 1&lt;br /&gt;
  color.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Color Code,                  C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  CATEGORY$,      General Category of Color,   C    6&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
&lt;br /&gt;
Then the functions would do the same thing as the following individual lines of code (assuming the next available file handle was 5):&lt;br /&gt;
&lt;br /&gt;
  DIM FORM$(5)*255&lt;br /&gt;
  DIM COLOR$(9)*1023, COLOR(1)&lt;br /&gt;
  OPEN #5: “Name=color.dat, kfname=color.key”,internal,outin,keyed&lt;br /&gt;
  LET FORM$(5)=”form C 6,V 30,V 6,C 6”&lt;br /&gt;
  LET FORM$(5)=CFORM$(FORM$(5))&lt;br /&gt;
  LET COLORFILE=5&lt;br /&gt;
  CO_CODE=1&lt;br /&gt;
  CO_NAME=2&lt;br /&gt;
  CO_CATEGORY=3&lt;br /&gt;
  CO_HTML=4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The data is used by referencing the file array, with the subscript name, so the color’s description becomes color$(co_Name).&lt;br /&gt;
&lt;br /&gt;
In the old days, if we wanted to change the file layout of our file, all of the programs that used that file would have to be changed one at a time to use the new file layout. Also, if the order of the fields changed, then all the programs would have to also be changed to use the new fields.&lt;br /&gt;
&lt;br /&gt;
But now, using this function, we can change the file layout all we want. If we later want to insert a field into the file layout before color name, I won’t have to look at this program again; this program will just work fine, because the library maps the subscripts to the actual fields.&lt;br /&gt;
&lt;br /&gt;
Also, the code is easier to read and maintain.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
The whole thing looks like this:&lt;br /&gt;
&lt;br /&gt;
  01025    ! Dimension the Arrays&lt;br /&gt;
  01030    DIM color$(1)*1023,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*1023,colorcat(1)&lt;br /&gt;
  01050    DIM form$(1)*255&lt;br /&gt;
  02000 !&lt;br /&gt;
  02020 library &amp;quot;fileio.br&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$) ! Open the file&lt;br /&gt;
  05000 ! &lt;br /&gt;
  30120    read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore ! Read the file&lt;br /&gt;
  30180    LET ColorCode$=color$(co_Code) !:&lt;br /&gt;
           LET ColorName$=color$(co_Name) ! Use the data by referincing it in the file arrays&lt;br /&gt;
  80000 !&lt;br /&gt;
  90000 ! Every program using fileio needs the following code&lt;br /&gt;
  99010  OPEN: ! ***** Function To Call Library Openfile And Generate Subs&lt;br /&gt;
  99020     def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, Dont_Sort_Subs, Path$*255, Mat Descr$, Mat Field_Widths)&lt;br /&gt;
  99030        dim _FileIOSubs$(1)*800&lt;br /&gt;
  99040        let Fnopen=Fnopenfile(Filename$, Mat F$, Mat F, Mat Form$, Inputonly, Keynum, Dont_Sort_Subs, Path$, Mat Descr$, Mat Field_Widths, Mat _FileIOSubs$)&lt;br /&gt;
  99050        for Index=1 to udim(mat _FileIOSubs$) : execute (_FileIOSubs$(Index)) : next Index&lt;br /&gt;
  99060     fnend&lt;br /&gt;
&lt;br /&gt;
== File Layouts ==&lt;br /&gt;
Now lets inspect the anatomy of a properly formatted file layout. These should be placed in a subdirectory called filelay.&lt;br /&gt;
&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  X,              Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
&lt;br /&gt;
The first line contains the name of the Farm File, a unique string to prefix all of your subscript pointers, and the file version number. The subscript value is to ensure that the program knows the difference between the Farm File’s Farm Code, and the Route File’s Route Code. (One will be RT_CODE and the other is FM_CODE).  These are separated by a comma. Spacing does not matter, so adjust your spacing so that it looks nice.&lt;br /&gt;
&lt;br /&gt;
The Version number is used to determine when the data has changed, and an update needs to be made to your data file. Your file layouts should all start at version 0, and each time you want to make a change, you may increment this value by 1.&lt;br /&gt;
&lt;br /&gt;
Each time you open a file with the FILEIO library, it reads the file version number of the file on disk (using the BR version() function), and then it compares it to the version number in your file layout. If your file layout has a higher version number then your existing data file, then the library opens the backup of the file layout for the version of the data file that exists on disk. It makes a backup copy of the existing data file, and creates a new file with the proper version number. Then it reads your records one at a time, and copies all the data from the old file into the new file one field at a time. If a field is dropped from the file layout, that data gets lost. If fields are rearranged, the data is copied and saved in the new file in the new positions. If a new field is added, it starts out blank (or 0).&lt;br /&gt;
&lt;br /&gt;
If you look in the filelay folder, you will notice a version folder. This contains several files ending with a number. For example you may see a color.0, and a color.1 file.&lt;br /&gt;
&lt;br /&gt;
If you run the fnopen function and it can not find your data file (usually because this is a new file and it hasn’t been created yet), &#039;&#039;the library will automatically create your file,&#039;&#039; based on the information you give in the first part of the file layout.&lt;br /&gt;
&lt;br /&gt;
Also, whenever you make changes to your file layout, the function library will automatically update the data files on disk for you. It does this by renaming the old file, creating a new one with the new version number, and then copying the data from the old one to the new one a record at a time.&lt;br /&gt;
&lt;br /&gt;
Any time it creates a file, or updates the file on disk, it creates a backup of the file &#039;&#039;layout&#039;&#039;. The first time you run a program that tries to read your new data file, it will create the data file for you and make a backup of the layout, and if the number in your file layout is 0, then it will create, for example, a filelay\version\price.0 file, a backup of your file layout that the library uses to figure out what has changed the next time you try to update the file.&lt;br /&gt;
&lt;br /&gt;
If you wish to make any changes to this data file, first you increment the version number, (in this case make the 0 into a 1). Then change the file layout all you want. You may rearrange fields, add new fields, add or remove keys, or change the record length.&lt;br /&gt;
&lt;br /&gt;
The only step necessary for having your data files updated is to increment the version number every time you make a change to the file layout.&lt;br /&gt;
&lt;br /&gt;
You may make any changes you like to the file layouts, but do not change the names of your existing subscripts. If you change the subscript name, not only will all the programs that reference that subscript be broken, but additionally, the routine will not understand that you are changing the name. It will think you are dropping the old field and adding a new field and any data stored in this location will be lost when the file is updated.&lt;br /&gt;
&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
&lt;br /&gt;
The second line contains the name of the first key, and a definition telling what the key is based on. These are separated by a comma. The key definition is made up of each of the subscript names in this file that form the keyfields for the file. When the library is called to open a file, if the file does not exist, or if it needs to be updated, a new one will be created. The function will read these subscript names that form your key definitions, and it will calculate the proper key position (KPS=) and length (KLN=) values. Then the create routine will use this information with the Index command to create the new key files.&lt;br /&gt;
&lt;br /&gt;
  price.key, ITEM&lt;br /&gt;
  price.ky2, FARM&lt;br /&gt;
  price.ky3, ITEM/FARM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
&lt;br /&gt;
Notice that the third key is based on three different fields. These are separated by a “/”. It is important that you use a “/” to separate your keys when you are building a key out of more then one field, because the function uses this “/” to help it make the proper BR syntax for defining complex key fields.&lt;br /&gt;
&lt;br /&gt;
The file can have as many keys as you want. The function will keep parsing key file names until it reaches the next part of the layout. It opens any OutIn files with all keys so that any changes you may make to the data stored on disk will be properly reflected in all the key files.&lt;br /&gt;
&lt;br /&gt;
The optional RECL= Parameter is read and used whenever a new file is created or an old one is updated. If it is not specified, the record length is calculated from the fields in the layout.&lt;br /&gt;
&lt;br /&gt;
  ===================================================&lt;br /&gt;
&lt;br /&gt;
The next line in the file is skipped by the parsing routine, and its purpose is to make the file layouts more readable to a programmer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
&lt;br /&gt;
Following the file and key structure, the fields are defined. There are three parameters on each field definition line, and you make one line for each field in your file layout. The first parameter is the subscript name that you will use in your program to refer to this data element. Place a $ at the end of the subscript name for all string elements. Don’t place anything at the end of the subscript name for numeric elements. Note that each of these names will be prefixed by the second parameter of the very first line of this layout. &lt;br /&gt;
&lt;br /&gt;
The second parameter is the description. This description is for the benefit of the programmer, so when the programmer is reading the file layouts, (s)he can tell which field does what. The spaces are ignored, so you may include as many spaces as you wish to make the layout look good. It does seem like good general guidelines would be to limit your layout lines to 255 characters and your descriptions to 80. &lt;br /&gt;
&lt;br /&gt;
The description is also used by the built in DataCrawler, a program that reads any of your data files and displays the entire contents in raw form in a listview. The Descriptions become the headings for each column in the listview. &lt;br /&gt;
&lt;br /&gt;
Those descriptions are also used for the default captions for your fields if you use ScreenIO, a library for building GUI programs that itself builds off of fileio.&lt;br /&gt;
&lt;br /&gt;
The third parameter is the form statement, which is pretty straightforward. Any items with a form statement of type “X” will be ignored, except that the length will still be used to calculate the position on disk of all remaining fields in the record. The library will take X fields into consideration when building the form statement, but not at any other time.&lt;br /&gt;
&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
Comment line text must begin with an exclamation point, but it may be indented. Comment lines may appear anywhere (vertically) and are ignored. &amp;lt;br&amp;gt;&lt;br /&gt;
Blank lines are ignored as well.&lt;br /&gt;
&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
After the last field definition, an &#039;&#039;optional&#039;&#039; #eof# line may be specified, in which case any lines after that will be ignored. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  DUMMY,          Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  ! default cost is normally zero&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
  #eof#&lt;br /&gt;
  additional comments...&lt;br /&gt;
&lt;br /&gt;
And that’s all there is to it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tips ===&lt;br /&gt;
&lt;br /&gt;
When you&#039;re making new layouts, a missing comma can cause FileIO to parse the layout wrong and give you errors. Here are a couple tips to help ensure your layouts are error free before using them in your programs.&lt;br /&gt;
&lt;br /&gt;
*Use the Data Crawler to test your layout. The data crawler is the simplest way to test your new layout without writing any code. It opens it and accesses the file in a very simple and straight forward manor to help identify any errors in the layout that you might have.&lt;br /&gt;
&lt;br /&gt;
*If you have trouble with the form statement, you can&#039;t see whats in it because FileIO uses CForm$ to compile your form statement to make your programs run faster. But here&#039;s a way to tell what the original form statement was that FileIO generated when it put the strings first and numbers last in your program: Open the file in the Data Crawler. When you get an error, type &amp;quot;Print FormStatement$&amp;quot; to see the original form statement.&lt;br /&gt;
&lt;br /&gt;
This works even if your file is working fine. Any time the file is opened with the data crawler, you can press CTRL-A and then type PRINT FormStatement$ and it will print out the uncompiled form statement for the file.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
Now that you have your file layouts defined, you have access to several powerful utilities right out of the box using Fileio. Additionally, several more utilities are available as [[#FileIO_Add-on_Packages|Add-Ons]], including our most popular development tool [[Screenio|ScreenIO]]. You can read more about them in their section below.&lt;br /&gt;
&lt;br /&gt;
But for now, lets take a look at some of the wonderful free utilities that come built into Fileio.&lt;br /&gt;
&lt;br /&gt;
Some of these utilities are accessible from your code via library functions, but the primary way you access any of them is by simply loading the FileIO Library and running it directly.&lt;br /&gt;
&lt;br /&gt;
=== DataCrawler ===&lt;br /&gt;
The data crawler is the original utility of FileIO. This utility shows you first a list of all data files allowing you to select one.&lt;br /&gt;
&lt;br /&gt;
Select a data file and press enter, and FileIO will then display a listview containing all the data in the data file. This list is sized based on the size of your main BR window (window 0) automatically to take up the full size available to it, so if you want to see more, try [[Open Window|opening window 0]] larger before running FileIO.&lt;br /&gt;
&lt;br /&gt;
At the top of the window is a filter box, and you can type anything you want in there and click &amp;quot;Refresh&amp;quot; and it will reread the data file, shortening the list to show only those records that match (case insensitive) what you have typed.&lt;br /&gt;
&lt;br /&gt;
If you have ScreenIO installed, then FileIO&#039;s data crawler will take advantage of the included Animation Engine in ScreenIO to animate a loading window while the listview is displaying. If you don&#039;t have ScreenIO then FileIO will simply load the listview.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want to wait for the entire file to load, press ESC to stop the load process.&lt;br /&gt;
&lt;br /&gt;
If the file is empty, FileIO will display a message box letting you know.&lt;br /&gt;
&lt;br /&gt;
This tool is very useful for sorting out data errors. It will allow you to look inside any data file you have a layout for and directly view the data there.&lt;br /&gt;
&lt;br /&gt;
At the bottom of the Data Crawler are several buttons. There&#039;s a Jump button that repositions the file by a key you specify and then loads the list with the data from that key on down to the end of the file.&lt;br /&gt;
&lt;br /&gt;
There is a &amp;quot;Columns&amp;quot; button which you can use to decide which columns should show up on the listview. Fewer columns means faster loading so sometimes for large files I press ESC immediately when the file first starts loading to cancel the load. Then I click &amp;quot;Columns&amp;quot; and check only the columns I want to see. Finally I press the &amp;quot;Refresh&amp;quot; button to trigger it to read the file again and this time it loads much faster then before.&lt;br /&gt;
&lt;br /&gt;
Next you&#039;ll find an Export button which starts the process for exporting a file to CSV. You can read more on that in the next section. And next to that is a Quit button.&lt;br /&gt;
&lt;br /&gt;
In this example, we loaded the file &amp;quot;Read Only&amp;quot; so it put everything in a listview. But there are times when its useful to fix data errors this way too, especially during development. So if you want to directly edit your data file, on the first page select the file you want to edit and instead of pressing &amp;quot;Enter&amp;quot; or clicking &amp;quot;View&amp;quot;, this time press &amp;quot;F5&amp;quot;. F5 is the secret Edit button that loads a data file into a grid instead.&lt;br /&gt;
&lt;br /&gt;
You can use the grid to change records, delete them or add them, and in addition to the buttons listed above, it also has an &amp;quot;Import&amp;quot; button for importing a CSV file into this data file.&lt;br /&gt;
&lt;br /&gt;
Any changes you make to the data file are not saved until you click the &amp;quot;Save&amp;quot; button (which also only appears when you&#039;re in Edit mode).&lt;br /&gt;
&lt;br /&gt;
In the 01/2015 release of FileIO, each records rec # is displayed in the listview, to aid in debugging bad data problems.&lt;br /&gt;
&lt;br /&gt;
==== Debugging Tip ====&lt;br /&gt;
Any time you&#039;re viewing a file layout in the Data Crawler, you can see the Uncompiled Form Statement by pressing CTRL-A to get to an ATTN prompt, and then entering the command:&lt;br /&gt;
&lt;br /&gt;
  print FormStatement$&lt;br /&gt;
&lt;br /&gt;
and it will print out the original form statement.&lt;br /&gt;
&lt;br /&gt;
==== Another Debugging Tip ====&lt;br /&gt;
&lt;br /&gt;
The FileIO Datacrawler ignores records that it cannot read. This is to allow for data files that have multiple record layouts in one data file. You make a custom layout for each record type and the data crawler shows just the records that match that type in the file.&lt;br /&gt;
&lt;br /&gt;
However that becomes a problem when you&#039;re making a layout to work with an existing data file. Error 726 indicates that something minor in the file layout doesn&#039;t match the data on the disk, but these errors are ignored so you might see either an empty data file, or a data file with some records missing. If that happens, you need to see the missing records in order to figure out what is wrong with your layout. &#039;&#039;&#039;&#039;&#039;It&#039;s very important that you don&#039;t try to use a file layout that isn&#039;t quite working right. Make sure your layout works and can read every record of a file that it should read before using it.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To see the records that could not be read in a file, run the data crawler on the layout, then press CTRL-A to get an ATTN prompt. From there, enter the command&lt;br /&gt;
&lt;br /&gt;
  print mat BadRead$&lt;br /&gt;
&lt;br /&gt;
and it will print all the records that were ignored because the file layout didn&#039;t match them. It prints out the raw data from the file.&lt;br /&gt;
&lt;br /&gt;
==== Function Access to use Data Crawler in your programs ====&lt;br /&gt;
You can use the data crawler in your own programs by using one of the following functions:&lt;br /&gt;
* [[#fnDataCrawler|fnDataCrawler]] - Open a Listview showing the data file&lt;br /&gt;
* [[#fnDataEdit|fnDataEdit]] - Display the data in an editable grid&lt;br /&gt;
* [[#fnShowData|fnShowData]] - This function does the same thing as the above two, but with many many more options allowing you to customize exactly what appears and exactly what they&#039;re allowed to change.&lt;br /&gt;
&lt;br /&gt;
Note: its not recommended to allow your customers to use the data crawler to access your data files directly. There&#039;s no way to specify validations or do anything complicated, so unless you&#039;re careful, there are lots of ways your customers could use this tool to do damage to your data files. It is a programmer tool only.&lt;br /&gt;
&lt;br /&gt;
If you do decide to use it for your end users, be careful how you implement it.&lt;br /&gt;
&lt;br /&gt;
=== Import/Export to CSV ===&lt;br /&gt;
&lt;br /&gt;
You can use FileIO to export your data files to CSV or import from CSV into your data file. To do this, you want to run the data crawler and select the file layout you&#039;re looking for. Then, view it (or press F5 to edit if you want to import something). Click on the Export button and it will ask you to select a file. Once that is selected it will ask a couple other simple questions, and when you&#039;ve specified the options to your satisfaction, click the Export! button. A new CSV file will be created.&lt;br /&gt;
&lt;br /&gt;
Import is even more simple. To import, you must be in Edit mode (press F5 to select the file instead of the enter key) and then simply select the Import button. It will ask you again to choose the file, and then it will ask you if it should update all files by Record Number (if record number is recorded in the CSV file) or by Key (if the file has keys) or to just Add all information to the file. Select what you want and press Import and the CSV file is added to the BR data file.&lt;br /&gt;
&lt;br /&gt;
==== Function Access to Import/Export from your programs ====&lt;br /&gt;
&lt;br /&gt;
You can use the following functions to call the Import and Export functionality from your code.&lt;br /&gt;
&lt;br /&gt;
*[[#fnCSVImport|fnCSVImport]]&lt;br /&gt;
*[[#fnCSVExport|fnCSVExport]]&lt;br /&gt;
&lt;br /&gt;
These functions are intended to give you the ability to use our functionality to write your own import and export routines for your customers, because its not a good idea to let your customers run the Data Crawler.&lt;br /&gt;
&lt;br /&gt;
=== Generate Layout Wizard ===&lt;br /&gt;
&lt;br /&gt;
There is also a Generate Layout Wizard utility in FileIO. This utility is there to help you build your file layouts. It is designed to work with a certain style of BR programming that was common in the 80s and 90s. So if your software is written in a style that opens the file directly, and reads/writes the data to a long series of individual variables, the Generate Layout Wizard is for you.&lt;br /&gt;
&lt;br /&gt;
To use it, start by running FileIO. Then, don&#039;t select a layout - instead, click on the &amp;quot;Generate Layout&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
You&#039;ll see a screen with a bunch of large text boxes, a small grid, and some buttons.&lt;br /&gt;
&lt;br /&gt;
The first thing you want to do is select the &amp;quot;Browse&amp;quot; button and then select a .wb or .br file that contains a program that reads or writes Most of the File.&lt;br /&gt;
&lt;br /&gt;
When you select one, press the Scan All button and it fileio will search the whole program looking first for all the open strings. It will take the file that is opened the most times and then search for all read statements to that file. It will look for the longest read statement and then find the Form statement associated with that Read statement, and any DIM statements for any variables used.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t like the file its chosen, click the &amp;quot;Open Scratch Pad&amp;quot; button to open the temp work file it uses into the program of your choice (I use myEdit for BRS files). Simply select all the open statements for the file you DO want to build off of, then click the Paste button to paste those open statements into the &amp;quot;Open String&amp;quot; list. After that click &amp;quot;Clear All&amp;quot; to erase what it did on the first search and then click &amp;quot;Scan All&amp;quot; again to rescan the program using this new data file.&lt;br /&gt;
&lt;br /&gt;
You may have to help it a bit, but once it has a proper matching open statement, read statement, form statement and dim statements for any arrays used, press the &amp;quot;Generate Layout&amp;quot; button and it will build a layout for that file.&lt;br /&gt;
&lt;br /&gt;
Finally, load the layout it built and clean up anything if you want, and consider adding better descriptions for each of the fields that you know (as it will use the variable names for both the subscripts AND descriptions in the layout).&lt;br /&gt;
&lt;br /&gt;
When you&#039;re all done, click &amp;quot;Done&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Functions to Generate Layouts from your code ====&lt;br /&gt;
&lt;br /&gt;
* [[#fnGenerateLayout_.26_fnWriteLayout|fnGenerateLayout]]&lt;br /&gt;
* [[#fnGenerateLayout_.26_fnWriteLayout|fnWriteLayout]]&lt;br /&gt;
&lt;br /&gt;
=== Code Templates ===&lt;br /&gt;
&lt;br /&gt;
One more tool FileIO has to help is the ability to generate code based on your file layouts.&lt;br /&gt;
&lt;br /&gt;
Run FileIO and this time select a file layout and press &amp;quot;Generate Code&amp;quot;. A window will pop up listing all the &amp;quot;Code Templates&amp;quot; that are available. Select one (and then select a key if it asks you - some templates require extra info). It looks like nothing happened, but the code you generated is now in your clip board. Paste it somewhere and take a look at it!&lt;br /&gt;
&lt;br /&gt;
Code Templates help us to standardize our ways of doing things, which eventually leads to more and more powerful tools we can use. Code Templates also help ensure we use cleaner code by doing some of the busy-work of writing clean code for us.&lt;br /&gt;
&lt;br /&gt;
==== Writing Code Templates ====&lt;br /&gt;
FileIO ships with several basic code templates. If you want to add your own, take a look in the filelay\templates folder (configurable in fileio.ini) and look at basic.brs. Copy it to your own program and then modify it to have your own code templates in it. Write me at gabriel.bakker@gmail.com with any questions. I want to help.&lt;br /&gt;
&lt;br /&gt;
And if you write good code templates, its easy to share them with the BR community. Anyone can download your templates and place them in this folder and they&#039;ll instantly be available for use.&lt;br /&gt;
&lt;br /&gt;
== FileIO Function Reference ==&lt;br /&gt;
&#039;&#039;The FileIO Library contains a number of other useful functions.&#039;&#039; The following functions are available and you are welcome to use them:&lt;br /&gt;
&lt;br /&gt;
=== Primary Functions ===&lt;br /&gt;
&lt;br /&gt;
==== fnOpen ====&lt;br /&gt;
fnOpen is the primary function that opens a file, and it’s used like so:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;def Fnopen(Filename$*255, Mat F$, Mat F, Mat Form$; Inputonly, Keynum, DontSortSubs, Path$*255, Mat Descr$, Mat FieldWidths, SupressPrompt, IgnoreErrors, SuppressLog)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note that all of the parameters after MAT Form$ are optional. If you need to specify a parameter in the middle of the optional parameter group, just list zeroes and empty strings for the intervening unused parameters. &lt;br /&gt;
&lt;br /&gt;
*FileName$ - The filename of the file layout for the file you’re reading.&lt;br /&gt;
*MAT F$ - The array that will be used to hold the string data for the file.&lt;br /&gt;
*MAT F – The array that will hold the numeric data for the file.&lt;br /&gt;
*MAT Form$ - An array of form statements.&lt;br /&gt;
*InputOnly – 1 means open for input only. 0 means open for OutIn and open every key file associated with the given data file (this is because all key files need to be open for the keys to be updated on an output) (defaults to 0). Files opened for input process considerably faster than files opened for output. Furthermore when files are opened for input only, alternate key files are &#039;&#039;not&#039;&#039; opened.&lt;br /&gt;
*KeyNum – This tells the function of which key to return the file handle (defaults to 1).&lt;br /&gt;
*DontSortSubs – The function by default, when compiling the Form statement, will sort the string and numeric subs in order to allow for reading the data into an array, and this parameter would turn this functionality off. However, if you are trying to read your data without reading it into an array, you are missing out on some serious efficiencies. You should normally leave this option turned off (0). This is a totally unsupported feature, and should always be set to 0, if it is specified at all.&lt;br /&gt;
*Path$ - The path to your data files. This optional parameter can be passed in by the calling function. It is prefixed to the beginning of the paths given in the file layout files. It is useful when your data files can be in different locations depending on the state of your program.&lt;br /&gt;
*mat Description$ - This optional parameter provides a way to read the description for each field from the original file layout. If the parameter is not provided, no description data will be returned. &lt;br /&gt;
*mat Fieldwidths – This optional parameter will return an array of the calculated display field widths. This number will always be at least large enough to contain the data for this field.&lt;br /&gt;
*SuppressPrompt - This optional parameter can be used to suppress the prompt normally given when fileIO creates a file. It can have three values. A value of 0, the default, uses the setting stored in your FileIO fnSettings routine to determine weather or not to prompt on Creation of a new file. A nonzero value always suppresses the prompt. A value of 1 indicates never to create a file if the file doesn&#039;t exist. A value of 2 automatically creates the file if the file doesn&#039;t exist.&lt;br /&gt;
*IgnoreErrors - Normally when fileio opens a data file, if there are errors trying to open the file, it prints them out to the debug console and pauses so that you can try to find out whats going wrong. If you specify 1 for &amp;quot;IgnoreErrors&amp;quot; it will cause Fileio to log those errors instead, and continue loading your program. This will result in the fnOpen file function returning Zero instead of the opened file number, so if you use IgnoreErrors, you need to test to make sure that fnOpen returned a file number before you try to access the file.&lt;br /&gt;
*SuppressLog - this optional parameter can be used to suppress writing to the log file for this one specific open statement. I use it for files that will be opened all the time, for example, the menu data file on one of my customers systems. Without this boolean parameter, his log file is quickly filled up with useless information any time his employees look at his menu. I specify this optional parameter to suppress logging anything about the menu file so that I can more easily find the actual programs they&#039;ve used when looking in the logfile.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Note: When using fnOpenFile, you really want to call your local function fnOpen, which in turn calls fnOpenFile for you.&#039;&#039;&#039;&#039;&#039;  FnOpenFile is for internal use only.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  Let FFILE=FNOPEN(“FARM”,MAT FARM$,MAT FARM,MAT FORM$,0,2)&lt;br /&gt;
  Let RFILE=FNOPEN(“ROUTE”,MAT ROUTE$,MAT ROUTE,MAT FORM$,1,3)&lt;br /&gt;
  Let CFILE=FNOPEN(“CUSTOMER”,MAT CUSTOMER$,MAT CUSTOMER,MAT FORM$)&lt;br /&gt;
&lt;br /&gt;
assuming:&lt;br /&gt;
  farm.dat has 3 keys: farm.ky1, farm.ky2, farm.ky3&lt;br /&gt;
  route.dat has 4 keys: route.ky1 … route.ky4&lt;br /&gt;
  customer.dat has 2 keys: customer.ky1, customer.ky2&lt;br /&gt;
&lt;br /&gt;
This will perform the following opens and set the following variables:&lt;br /&gt;
&lt;br /&gt;
  OPEN #1: “Name=Farm.Dat, kfname=farm.ky2”,internal,outin,keyed&lt;br /&gt;
  OPEN #2: “Name=Farm.Dat, kfname=farm.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #3: “Name=Farm.Dat, kfname=farm.ky3”,internal,outin,keyed&lt;br /&gt;
  OPEN #4: “Name=Route.Dat, kfname=route.ky3”,internal,input,keyed&lt;br /&gt;
  OPEN #5: “Name=Customer.Dat,kfname=customer.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #6: “Name=Customer.Dat,kfname=customer.ky2”,internal,outin,keyed&lt;br /&gt;
  LET FFILE=1&lt;br /&gt;
  LET RFILE=4&lt;br /&gt;
  LET CFILE=5&lt;br /&gt;
&lt;br /&gt;
This will also resize the arrays, set the form statement, and create all the subscripts to make accessing the data clear and simple, as in the above example. The KEYNUM parameter is where you list the key file you would like to use for reading and writing. The extra keys are opened to ensure that all keys get updated properly when the file is changed.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  DIM FORM$(1),PRICE$(1)*255,PRICE(1),&lt;br /&gt;
  DIM DESCRIPTION$(1)*80,FIELDWIDTHS(1)&lt;br /&gt;
&lt;br /&gt;
  Let PRICEFILE=FNOPEN(“PRICE”,MAT PRICE$,MAT PRICE,MAT FORM$,0,2,0,&amp;quot;&amp;quot;,MAT DESCRIPTION$)&lt;br /&gt;
&lt;br /&gt;
Assuming the Price File layout (filelay\price) contains:&lt;br /&gt;
&lt;br /&gt;
  price.dat, PR_, 1&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  DUMMY,          Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
  DESCRIPTION$,   Description of Price Rule,   C   30&lt;br /&gt;
 &lt;br /&gt;
This will perform the following opens and set the following variables:&lt;br /&gt;
&lt;br /&gt;
  OPEN #1: “Name=Price.Dat, kfname=Price.ky2”,internal,outin,keyed&lt;br /&gt;
  OPEN #2: “Name=Price.Dat, kfname=Price.ky1”,internal,outin,keyed&lt;br /&gt;
  OPEN #3: “Name=Price.Dat, kfname=Price.ky3”,internal,outin,keyed&lt;br /&gt;
  let PRICEFILE=1&lt;br /&gt;
  let PR_FARM=1&lt;br /&gt;
  let PR_ITEM=2&lt;br /&gt;
  let PR_GRADE=3&lt;br /&gt;
  let PR_DESCR=4&lt;br /&gt;
  let PR_PRICE=1&lt;br /&gt;
  let PR_COST=2&lt;br /&gt;
  let PR_XOPRICE=3&lt;br /&gt;
  let PR_XOCOST=4&lt;br /&gt;
  let PR_MOPRICE=5&lt;br /&gt;
  let PR_MOCOST=6&lt;br /&gt;
  let PR_VOPRICE=7&lt;br /&gt;
  let PR_VOCOST=8&lt;br /&gt;
  MAT FORM$(1)&lt;br /&gt;
  MAT PRICE$(4)&lt;br /&gt;
  MAT PRICE(8)&lt;br /&gt;
  MAT DESCRIPTION$(12)&lt;br /&gt;
  MAT FIELDWIDTHS(12)&lt;br /&gt;
  let FORM$(1)=CFORM$(”form C 4,C 4,C 4,POS 74,C 30,POS 50,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2,BH 3.2”)&lt;br /&gt;
  let Description$(1)= “Farm Code (or blank)”&lt;br /&gt;
  let Description$(2) = “Item Code”&lt;br /&gt;
  let Description$(3) = “Quality”&lt;br /&gt;
  let Description$(4) = “Description of Price Rule”&lt;br /&gt;
  let Description$(5) = “Default Price”&lt;br /&gt;
  let Description$(6) = “Default Cost”&lt;br /&gt;
  let Description$(7) = “Default Christmas Price”&lt;br /&gt;
  let Description$(8) = “Default Christmas Cost”&lt;br /&gt;
  let Description$(9) = “Default Mothers D Price”&lt;br /&gt;
  let Description$(10) = “Default Mothers D Cost”&lt;br /&gt;
  let Description$(11) = “Default Valentine Price”&lt;br /&gt;
  let Description$(12) = “Default Valentine Cost”&lt;br /&gt;
  let FieldWidths(1) = 4&lt;br /&gt;
  let FieldWidths(2) = 4&lt;br /&gt;
  let FieldWidths(3) = 4&lt;br /&gt;
  let FieldWidths(4) = 30&lt;br /&gt;
  let FieldWidths(5) = 8&lt;br /&gt;
  let FieldWidths(6) = 8&lt;br /&gt;
  let FieldWidths(7) = 8&lt;br /&gt;
  let FieldWidths(8) = 8&lt;br /&gt;
  let FieldWidths(9) = 8&lt;br /&gt;
  let FieldWidths(10) = 8&lt;br /&gt;
  let FieldWidths(11) = 8&lt;br /&gt;
  let FieldWidths(12) = 8&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
There are a few things I’d like to point out about the example above. First, you will notice that the form statement jumps around to put all the strings first, and then the numbers last. This is why it has a “POS 74, C 30,POS 50”. Then notice that the subscripts for the string variables are 1 .. 4, and the subscripts for the numbers are 1 .. 8. Finally, the order of the Description and FieldWidth fields also match the sorted positioning of the Form Statement.&lt;br /&gt;
&lt;br /&gt;
The reason that we sort our form statements is so that BR will allow us to read the file into arrays by saying:&lt;br /&gt;
&lt;br /&gt;
  Read #pricefile, using form$(pricefile) : mat price$, mat price&lt;br /&gt;
&lt;br /&gt;
Without resorting, the above statement would give a conversion error as BR attempted to put the PR_PRICE field inside mat price$(4). However, because we have reordered the form statement, we are able to read them safely into two arrays, and then we will be able to use the values without caring what position they are in the file, by simply saying PRICE$(PR_DESCRIPTION) when we want the description, and PRICE(PR_PRICE) when we want the pr_Price field.&lt;br /&gt;
&lt;br /&gt;
Another thing you may notice about the above example is that it gives the calculated display length for the numeric fields as 8, when on the disk (and in the file layout) they are listed as BH 3.2. The reason for this is the program looks at the BH 3, and figures that a number that takes up 3 bytes on disk has a potential maximum size of 256**3 or 16,777,216, and therefore will need up to 8 characters of screen display space to view. &lt;br /&gt;
&lt;br /&gt;
Finally, note that any field with a form statement of X is ignored by the library, except that the blank space is used when building the FORM statement.&lt;br /&gt;
&lt;br /&gt;
==== fnCloseFile ====&lt;br /&gt;
This function will close the specified file number and all keys that were opened with the file.  The purpose of this function is to facilitate the closing of the extra keys that are opened when you open a file for OutIn with the library. There is no need to use this for files opened for input because it is easier to just close the file directly. Secondary keys are not opened by FileIO for files opened for input only. &lt;br /&gt;
&lt;br /&gt;
You must give the function the name of the file layout. It uses this information to determine how many keys were opened, and how many it must therefore close. &lt;br /&gt;
&lt;br /&gt;
Then it basically starts at the file number you gave it, and closes the next X files that were opened with the same file name as this, where X is the number of keys associated with this file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCloseFile(filenumber,filelay$;path$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FileNumber – The filenumber of the file you are trying to close.&lt;br /&gt;
*FileLay$ - The name of the file layout for this file. This is used to determine how many keys the file would have been opened with and therefore how many we now need to close.&lt;br /&gt;
*Path$ - Optional Alternate Path. Use to close files that were opened using the open file&#039;s optional alternate path parameter.&lt;br /&gt;
&lt;br /&gt;
==== fnGetFileNumber ====&lt;br /&gt;
FnGetFileNumber is a simple function to find a valid unused file handle. If you use this function in all of your programs, they will become much more portable, as you will never have to worry about your file handles fighting with each other. The function will return 0 if no free file number was found (but with 999 of them available now, I have never seen it happen).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnGetFileNumber(;X,Count)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*X – This optional parameter will specify where to start looking.&lt;br /&gt;
*Count - This optional parameter will specify how many file numbers to find in a row. If count is 3, then fnGetFileNumber will return the first filenumber in the first gap of three unused file numbers that it finds.&lt;br /&gt;
&lt;br /&gt;
=== File Reading Helper Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions perform various useful calculations to aid in interacting with data files when you&#039;re using fileio.&lt;br /&gt;
&lt;br /&gt;
==== fnBuildKey$ ====&lt;br /&gt;
This function will return the key for a given record in a data file. It actually reads the file layout and builds the key to match the layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnBuildKey$(Layout$, Mat F$, Mat F; Keynum)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the name of the data file to build the key for.&lt;br /&gt;
*Mat F$ - the string array of the file object&lt;br /&gt;
*Mat F - the numeric array of the file object&lt;br /&gt;
*KeyNum - This optional parameter specifies which of the key files in the given layout the key should be built for.&lt;br /&gt;
&lt;br /&gt;
To use this, you want some code like in the following example:&lt;br /&gt;
&lt;br /&gt;
  mat customer$=(&amp;quot;&amp;quot;) : mat Customer=(0)&lt;br /&gt;
  let customer$(cu_name)=CustName$&lt;br /&gt;
  let customer$(cu_phone)=CustPhone$&lt;br /&gt;
  read #customer, using form$(Customer), key=fnBuildKey$(&amp;quot;customer&amp;quot;,mat Customer$,mat Customer,2) : mat Customer$, mat Customer nokey KeyNotFound&lt;br /&gt;
  ! The above code assumes that the second key of the Customer file is based on the Name and Phone fields.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
By using this logic you are able to avoid directly specifying the key in your code - which means that even if the key changes in the future, as long as your code specifies enough information, it will still find the correct key. In our example, even if we dropped the phone number from the key in the future, or even if we expand the length of the Customer Name field, our code would still work and fnBuildKey$ would still build the correct key without us having to look at or change our code again.&lt;br /&gt;
&lt;br /&gt;
This kind of reasoning is central to the fileio system, which, when implemented properly, ensures that you can change your data files in any way you need to in the future, without breaking your existing programs.&lt;br /&gt;
&lt;br /&gt;
==== fnUniqueKey ====&lt;br /&gt;
This function tests to see if a given key is unique to the specified file. This function is very useful for situations where you need to ensure that the user-entered key is unique.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnUniqueKey(Fl,key$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file number of the opened file.&lt;br /&gt;
*Key$ - This is the key to test. If this key is the key for a preexisting record in the file, the function will return false. If this key can not be found in the file, the function will return true.&lt;br /&gt;
&lt;br /&gt;
==== fnMakeUniqueKey$ ====&lt;br /&gt;
This function generates a unique key for a given file. This is useful if you do not care what the key is, but it needs to be unique. I use this function in situations where the user never needs to know what the given key is. &lt;br /&gt;
&lt;br /&gt;
This function reads the key length for the given file. Then it returns a string that is the right length, which is generated by counting in binary until a key is found that does not appear in the file. The first key found for a 4 byte key field would be chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0). If that key was already in use in the file, the function would return chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(1). If that one was also in use, it would then try chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(0)&amp;amp;chr$(2), and so on until it found one that wasn’t in use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnMakeUniqueKey$(fl)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – This is the file number of the opened file for the desired key.&lt;br /&gt;
&lt;br /&gt;
==== fnKey$ ====&lt;br /&gt;
This function formats the key for the given file number. All it does is ensure the key is the correct length. You should use fnBuildKey$ instead to properly build the correct key for the record you want to read.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnKey$(FileNumber, Key$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileNumber - the file number we are formatting the key for&lt;br /&gt;
*Key$ - the key we are trying to format.&lt;br /&gt;
&lt;br /&gt;
==== fnNotInFile ====&lt;br /&gt;
This function will determine if a non-key element in a line is unique. It works almost exactly like fnUniqueKey specified above, except that it allows you to enter the subscript value of the element you are checking for uniqueness. You can use this to look for uniqueness in any field, not just in the key field. Additionally, the search engine used by this function looks for a partial match, and will only return true if the given string is not found anywhere in the specified element for the given file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnNotInFile(string$*100,filename$,sub)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - Value to check for uniqueness in this file.&lt;br /&gt;
*Filename$ - This is the name of the file layout of the file you want to check. This file does not have to be open in order for you to search it, because the function will open it for you.&lt;br /&gt;
*Sub – This is the subscript value of the element you are checking.&lt;br /&gt;
&lt;br /&gt;
==== fnSortKeys ====&lt;br /&gt;
This function takes an array of Primary Keys indicating records in the data file, and resorts it into the order you would have expected using one of the other keys for your data file.&lt;br /&gt;
&lt;br /&gt;
For example: Lets say you had a customer file, and the first key was Customer Code and the second key was Customer Last Name. This function would take an array of Customer Codes and sort it into Last Name order.&lt;br /&gt;
&lt;br /&gt;
This function requires the file to already be opened (which is usually the case when you have an array of keys from that file).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnSortKeys(mat Keys$,Layout$,DataFile,mat F$,mat F,mat Form$;KeyNum)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Keys$ - the array of keys. These keys are based on whatever key the file was opened with in DataFile.&lt;br /&gt;
*Layout$ - the file layout for the file.&lt;br /&gt;
*DataFile - the open file number matching the key file that matches mat Keys$.&lt;br /&gt;
*mat F$ - array sized to hold the strings from the data file. This is the array you get back from fnOpen.&lt;br /&gt;
*mat F - array sized to hold the numerics from the data file. This is the array you get back from fnOpen.&lt;br /&gt;
*mat Form$ - array of form statements, that you get back from fnOpen.&lt;br /&gt;
*KeyNum - This is the key that we&#039;ll sort based on. If not given, the first key listed in the layout is assumed.&lt;br /&gt;
&lt;br /&gt;
=== File Reading Functions ===&lt;br /&gt;
&lt;br /&gt;
These functions actually read information from your data file and return it. These functions can be used to simplify the logic in your programs for many common tasks.&lt;br /&gt;
&lt;br /&gt;
==== fnReadAllKeys ====&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record into (a) dynamically dimensioned array(s). For example, I could tell it to give me the Inventory Code for every inventory item in my database in one array, while placing the Inventory Description (name) for each item into the corresponding position in another array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadAllKeys(Fl,mat f$,mat f,mat fm$,sub1,mat out1$;sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – The file handle for the already opened file in question.&lt;br /&gt;
*mat F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array&lt;br /&gt;
*mat out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*mat out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If I wanted to implement the above example, I would say:&lt;br /&gt;
&lt;br /&gt;
  FnReadAllKeys(InventFile,mat Invent$,mat Invent,mat Form$,IN_Code,mat InvtList$,IN_Name,mat InvtNames$)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnReadMatchingKeys ====&lt;br /&gt;
&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record where the key matches the specified key into (a) dynamically dimensioned array(s). This function is the same as the above function except this one will filter the results, returning only those records where the key matches the specified key.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadMatchingKeys(Fl,mat f$,mat f,mat fm$,key$,keysub,sub1,mat out1$;sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*mat F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*mat fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Key$ - Only records where the key field matches key$ will be returned.&lt;br /&gt;
*Keysub – This tells the function which element is the key element for this particular file number.&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*mat out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnReadAllNewKeys ====&lt;br /&gt;
&lt;br /&gt;
This function will read through a file, returning the specified element(s) from each record that isn’t already there into (a) dynamically dimensioned array(s). This function is the same as the above function, except this one will filter the results returning only those records that don’t already exist in the array (eliminating duplicates).&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;FnReadAllNewKeys(Fl,mat f$,mat f,mat fm$,sub1,mat out1$; dont_reset,sub2,mat out2$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*MAT F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Dont_reset – By default the array will clear the contents of the arrays that are passed in. This Boolean flag will instruct the function to not empty the passed in arrays.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*MAT out2$ - Array in which to return the second (optional) parameter. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
==== fnReadFilterKeys ====&lt;br /&gt;
&lt;br /&gt;
This function by Mikhail Zheleznov is a modification of the above functions. Like its predecessors, it reads an entire file, populating the specified arrays with data from all or some of the records in the file. The given subscripts specify which fields to return from each record. The key given specifies search criteria for the records. The filter specifies filtering criteria that can be preformed on the data before it is returned. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadFilterKeys(Fl,Mat F$,Mat F,Mat Fm$,Key$,Keyfld,Sub1,Mat Out1$;Filter$,Filter_Sub,Readlarger,Sub2,Mat Out2$, Sub3, Mat Out3$, Sub4,Mat Out4$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FL – The file handle for the already opened file in question.&lt;br /&gt;
*MAT F$ - Work array with a size that corresponds to the number of string elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT F – Work array with a size that corresponds to the number of numeric elements in the record (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*MAT fm$ - Array of Forms statement. FM$(FL) must be the form statement for this file (this is calculated automatically in the Open statement, if you used this library to open the file).&lt;br /&gt;
*Key$ - The key to search for in the read statements&lt;br /&gt;
*Keyfld – the subscript of the key field in the data file. This must match the key field specified in the data file otherwise the function won’t work.&lt;br /&gt;
*Sub1 – Subscript of the element to return in the first array.&lt;br /&gt;
*MAT out1$ - Array in which to return the data. This array will be resized to match the number of records in the file.&lt;br /&gt;
*Filter$ – This optional parameter identifies matches to search for in the records. It works in conjunction with Filter_Sub&lt;br /&gt;
*Filter_Sub – This parameter specifies which field to look for in the records for matches to Filter$. Only records which have Filter$ in the specified field will be returned.&lt;br /&gt;
*Sub2 – Subscript of the element to return in the second array. This is optional. If it is specified, you must give MAT out2$, or BR will return an error.&lt;br /&gt;
*MAT out2$ - Array in which to return the second (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub2 is given (non-zero). This parameter will not be used if Sub2 is not given or is given as 0.&lt;br /&gt;
*Sub3 – Subscript of the element to return in the third array. This is optional. If it is specified, you must give MAT out3$, or BR will return an error.&lt;br /&gt;
*MAT out3$ - Array in which to return the third (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub3 is given (non-zero). This parameter will not be used if Sub3 is not given or is given as 0.&lt;br /&gt;
*Sub4 – Subscript of the element to return in the fourth array. This is optional. If it is specified, you must give MAT out4$, or BR will return an error.&lt;br /&gt;
*mat out4$ - Array in which to return the fourth (optional) field. This array will be resized to match the number of records in the file. This parameter MUST be provided when Sub4 is given (non-zero). This parameter will not be used if Sub4 is not given or is given as 0.&lt;br /&gt;
&lt;br /&gt;
This function was written by Mikhail Zheleznov for the fileIO library.&lt;br /&gt;
&lt;br /&gt;
==== fnReadDescription$ ====&lt;br /&gt;
&#039;&#039;fnReadDescription$(Fl,Subscript,key$,mat F$,mat F,mat Form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – File Handle for file to use (Route File).&lt;br /&gt;
*Subscript – Index of field in record to use (should be taken from file layout) (RT_NAME, which should equal 2 after opening routefile (unless we change the file layout later)).&lt;br /&gt;
*key$ - Item that should match a key in this file somewhere (in this case it is the route code from the farm record).&lt;br /&gt;
*mat F$ &amp;amp; mat F - Work Variables to hold a file record from the file we are reading they have to be dimensioned properly, which is why we use our colorcat$ and our colorcat for these parameters.&lt;br /&gt;
*mat Form$ - This will need to be our array of form statements, so the function can read the file properly.&lt;br /&gt;
&lt;br /&gt;
Lets take a look at how this function works:&lt;br /&gt;
&lt;br /&gt;
In the example program I used above, I am reading the Color File to get details about each color. The color file contains a colorcat code field, but I want to display the colorcat description. The colorcat file contains a few details about a color category, and it is indexed based on colorcat code:&lt;br /&gt;
&lt;br /&gt;
  route.dat, RT_&lt;br /&gt;
  route.key, CODE&lt;br /&gt;
  recl=512&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE,           Routing Code,                C    6&lt;br /&gt;
  NAME,           Routing Name Description,    C   30&lt;br /&gt;
  MOFT,           T/A/C (truck/air/courier),   C    1&lt;br /&gt;
  SHIPPINGDAY,    Day of Week for Shipping,    C    7&lt;br /&gt;
&lt;br /&gt;
Now, as you know, in the above example, we have already opened the ColorCat File, and we have opened and read a Color record.&lt;br /&gt;
 &lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  30120       read #colorfile, using form$(colorfile) : mat color$, mat color eof Ignore&lt;br /&gt;
  30180       LET ccode$=color$(CO_CODE) !:&lt;br /&gt;
              LET Name$=color$(CO_NAME)&lt;br /&gt;
&lt;br /&gt;
Now all that’s left to do is to take the Color File’s ColorCat code and use it to look up the ColorCat File’s description.&lt;br /&gt;
&lt;br /&gt;
  30190 LET ColorCat$ = fnReadDescription$(ColorCatFile, CC_NAME, Color$(CO_CATEGORY),&lt;br /&gt;
    mat ColorCat$, mat ColorCat, mat form$)&lt;br /&gt;
&lt;br /&gt;
==== fnReadUnopenedDescription$ ====&lt;br /&gt;
This function accomplishes the same thing as fnReadDescription except that it opens the data file for you. It is slower then FnReadDescription$, but it is easier to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadUnopenedDescription$(Layout$,key$*255;Field)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are reading&lt;br /&gt;
*key$ - the value of the key field in the record to be read&lt;br /&gt;
*Field - the element of the data file to return. If not given, this defaults to 2, so sometimes it is a good idea to design your data files so that string field number two is a descriptive field, like Name or Description.&lt;br /&gt;
&lt;br /&gt;
This function only works on the first key file for each data file. This function is a convenience function but it is slow because it opens the file and closes it for each call. Opening a file is one of the most time consuming program operations.&lt;br /&gt;
&lt;br /&gt;
==== fnReadNumber ====&lt;br /&gt;
&lt;br /&gt;
fnReadNumber does the same thing that ReadDescription does except it reads a numeric field instead of a description.&lt;br /&gt;
&lt;br /&gt;
Lets take a look at how this function works:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadNumber(Fl,subscript,key$,mat F$,mat F,mat fm$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Fl – File Handle for file to use (Route File).&lt;br /&gt;
*Subscript – Index of field in record to use (should be taken from file layout).&lt;br /&gt;
*Key$ - Item that should match a key in this file somewhere.&lt;br /&gt;
*mat F$ &amp;amp; mat F - Work Variables to hold a file record from the file we are reading. They have to be dimensioned properly by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat Fm$ - This will need to be our array of form statements, so the function can read the file properly.&lt;br /&gt;
&lt;br /&gt;
==== fnReadUnopenedNumber ====&lt;br /&gt;
This function accomplishes the same thing as fnReadNumber except that it opens the data file for you. It is slower then FnReadNumber, but it is easier to use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadUnopenedNumber(Layout$,key$*255;Field)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are reading&lt;br /&gt;
*key$ - the key of the record to be read&lt;br /&gt;
*Field - the element of the data file to return. If not given, this defaults to 2, so sometimes it is a good idea to design your data files so that string field number two is a descriptive field, like Name or Description.&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelativeDescription$ ====&lt;br /&gt;
This function is the same as fnReadDescription$ but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelativeDescription$(FileNumber,SubscriptToRead,RecordNumber,mat F$,mat F,mat form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Filenumber - The file number of the open data file&lt;br /&gt;
*SubscriptToRead - The subscript to read&lt;br /&gt;
*RecordNumber - the Record number to read&lt;br /&gt;
*mat F$ and mat F - the arrays to hold the data. They must match the dimensions and should be set with [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat form$ - the forms array is also set by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelUnopenedDescription$ ====&lt;br /&gt;
This is the same as ReadUnopenedDescription$ but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelUnopenedDescription(Layout$,RecordNumber;Field)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*RecordNumber - the record to read&lt;br /&gt;
*Field - the field subscript to read&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelativeNumber ====&lt;br /&gt;
This is the same as fnReadNumber but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelativeNumber(FileNumber,SubscriptToRead,RecordNumber,mat F$,mat f,mat Form$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Filenumber - The file number of the open data file&lt;br /&gt;
*SubscriptToRead - The subscript to read&lt;br /&gt;
*RecordNumber - the Record number to read&lt;br /&gt;
*mat F$ and mat F - the arrays to hold the data. They must match the dimensions and should be set with [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
*mat form$ - the forms array is also set by [[FileIO_Library#fnOpenFile|fnOpen]].&lt;br /&gt;
&lt;br /&gt;
==== fnReadRelUnopenedNumber ====&lt;br /&gt;
This is the same as fnReadUnopenedNumber but for Relative Files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadRelUnopenedNumber(LayoutName$,RecordNumber;Field)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*RecordNumber - the record to read&lt;br /&gt;
*Field - the field subscript to read&lt;br /&gt;
&lt;br /&gt;
==== fnReadRecordWhere$ ====&lt;br /&gt;
This function returns the record where the given element matches the given value. It does not depend on any key files, and it can be used to locate a record based on any element. However, it loops through the entire data file to do this and it could be a bit slow for large data files. This function opens the file for you, so the file does not have to be already opened.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadRecordWhere$(Layout$,SearchSub,SearchKey$*255,ReturnSub)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Layout$ - the layout of the file we are searching&lt;br /&gt;
*SearchSub - Subscript of the element to look in&lt;br /&gt;
*SearchKey$ - The value we are looking for&lt;br /&gt;
*ReturnSub - Subscript of the element to return&lt;br /&gt;
&lt;br /&gt;
=== FileIO Utility Functions ===&lt;br /&gt;
==== fnDataCrawler ====&lt;br /&gt;
This function launches the Data Crawler as a function, so you can make your own programs link to it. Special thanks to Mikhail Zheleznov for turning the DataCrawler into a library function.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDataCrawler(Layout$;SRow$,SCol$,Rows$,Cols$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnDataEdit ====&lt;br /&gt;
This function is the same as fnDataCrawler only it opens a Grid for editing.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDataCrawler(Layout$;SRow$,SCol$,Rows$,Cols$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== fnShowData ====&lt;br /&gt;
&lt;br /&gt;
This function builds a list or a grid in a floating window that is tied to a data file. It uses the same function that the datacrawler uses, but its much more customizable. All other datacrawler functions are just wrappers for this one.&lt;br /&gt;
&lt;br /&gt;
The first parameter is the only required parameter.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;def library fnShowData(FileLay$;Edit,sRow,sCol,Rows,Cols,KeyNumber,Caption$*127,Path$*255,KeyMatch$*255,SearchMatch$*255,CallingProgram$*255,mat Records,mat IncludeCols$,mat IncludeUI$,mat ColumnDescription$,mat ColumnWidths,mat ColumnForms$,DisplayField$*80,mat FilterFields$,mat FilterForm$,mat FilterCompare$,mat FilterCaption$,mat FilterDefaults$,mat FilterKey)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileLay$ - the file layout you want to display&lt;br /&gt;
*Edit - 1 for Edit (Grid) and 0 for View (Listview)&lt;br /&gt;
*sRow, sCol - the start position. if not given, its centered. If given but out of bounds, they&#039;ll be automatically adjusted to fit the grid on the screen.&lt;br /&gt;
*Rows, Cols - the size. If not given, defaults to fullscreen. If given but not big enough to fit the UI elements you request, they&#039;re automatically adjusted to fit everthing.&lt;br /&gt;
*KeyNumber - the Key to use when reading the data, used with other parameters. If not given, the file is read Relative for faster performance. Required if KeyMatch$ is given.&lt;br /&gt;
*Caption$ - the Caption to display, defaults to FileIO&#039;s Datacrawler&lt;br /&gt;
*Path$ - Alternate path to use for data files (Prepended to the name found in the layout)&lt;br /&gt;
*KeyMatch$ - Show only records that match this key. You can use Partial Keys. If this parameter is given, you must also give KeyNumber (above).&lt;br /&gt;
*SearchMatch$ - Show only records that contain this substring in them anywhere&lt;br /&gt;
*CallingProgram$ - used for logging purposes, pass in the system function Program$&lt;br /&gt;
*mat Records - Show only these records in the Grid. Use it to control exactly what the user sees.&lt;br /&gt;
*mat IncludeCols$ - Show only these columns. These column names must match the subscript names from the file layout.&lt;br /&gt;
*mat IncludeUI$ - Which UI Options to show. Build this array with one element for each optional UI element to include. Explanations of UI elements follow:&lt;br /&gt;
**&amp;quot;ColumnsButton&amp;quot; - adds a Select Columns button that the user can use to modify which columns appear on the list.&lt;br /&gt;
**&amp;quot;ExportButton&amp;quot; - adds an Export to CSV button that exports the data to a CSV file.&lt;br /&gt;
**&amp;quot;ImportButton&amp;quot; - adds an Import from CSV button that imports from the CSV file.&lt;br /&gt;
**&amp;quot;AddButton&amp;quot; - adds a button that can be used to add records to the data file.&lt;br /&gt;
**&amp;quot;SaveButton&amp;quot; - adds a button allowing the user to save changes&lt;br /&gt;
**&amp;quot;DeleteButton&amp;quot; - adds a button allowing the user to delete a row&lt;br /&gt;
**&amp;quot;KeyButton&amp;quot; - adds a button allowing the user to jump to a specified position by key or by record number (depending on if the file is opened keyed or not)&lt;br /&gt;
**&amp;quot;QuitButton&amp;quot; - adds a Quit button to the screen (the Esc key also quits)&lt;br /&gt;
**&amp;quot;Search&amp;quot; - adds a case insensitive search box to the screen.&lt;br /&gt;
**&amp;quot;Border&amp;quot; - adds a border around the screen&lt;br /&gt;
**&amp;quot;Caption&amp;quot; - adds a caption. (If you specify a caption, this is automatically turned on. If you don&#039;t specify a caption but turn on caption here, then FileIO uses the default FileIO data crawler caption.&lt;br /&gt;
**&amp;quot;Recl&amp;quot; - adds the Recl to the caption&lt;br /&gt;
**&amp;quot;Position&amp;quot; - adds the positions to the field descriptions in the column headings.&lt;br /&gt;
*mat ColumnDescription$ - Show these captions. If blank, use the descriptions from the layout&lt;br /&gt;
*mat ColumnWidths - Use these widths for the data, if not given, calculate from the file layout&lt;br /&gt;
*mat ColumnForms$ - Display Format for the data, including DATE and FMT and PIC&lt;br /&gt;
*mat DisplayField$ - Counter Field to display on the Loading Window. If its a field with an associated DATE ColumnForms$ value, that column form will be used when displaying the Counter Field. It can be any of the following:&lt;br /&gt;
**REC - this will display the current &amp;quot;REC/LREC&amp;quot; data in the loading window.&lt;br /&gt;
**READCOUNT - this will display the &amp;quot;Record Count / LREC&amp;quot; in the loading window.&lt;br /&gt;
**FINDCOUNT - this will display the number of records that match the current search criteria by itself in the loading window.&lt;br /&gt;
**A Field Name - one of your field names will display that field value in the loading window&lt;br /&gt;
**A string literal - anything else will display as a string in the loading window, so you could put something like &amp;quot;Loading, please wait&amp;quot; here and it will display.&lt;br /&gt;
*mat FilterFields$ - Contains the subscript of the field to compare to&lt;br /&gt;
*mat FilterForm$ - Contains the format of the field to compare to&lt;br /&gt;
*mat FilterCompare$ - Contains the comparison type (&amp;quot;&amp;lt;&amp;gt;&amp;quot; or &amp;quot;&amp;gt;&amp;quot; or &amp;quot;=&amp;quot; or &amp;quot;&amp;gt;=&amp;quot; or &amp;quot;*&amp;quot;) (* means do a substring search)&lt;br /&gt;
*mat FilterCaption$ - The caption for the filter box&lt;br /&gt;
*mat FilterDefaults$ - The default value for the filter information&lt;br /&gt;
*mat FilterKey - The action to use when filtering the data this way (0 means simple exclude, 1 means start here, -1 means stop here)&lt;br /&gt;
**The final five arrays can be used to add user filter boxes to the data grid. You need one element in each array for every custom user filter box on the screen.&lt;br /&gt;
&lt;br /&gt;
==== fnCSVImport ====&lt;br /&gt;
&lt;br /&gt;
This function calls the FileIO Import routine, the same one that you get from the Datacrawlers Import Button.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCsvImport(Layout$*64;SuppressDialog,FileName$*300,ImportModeKey)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout to import into&lt;br /&gt;
*SupressDialog - 1 to Supress the Import Dialog&lt;br /&gt;
*FileName$ - the name of the CSV file (Required if Dialog is Suppressed)&lt;br /&gt;
*ImportModeKey - the Import Mode Key (Required if Dialog is Suppressed)&lt;br /&gt;
**-1 - Add all records to the file&lt;br /&gt;
**0 - Update by Record Number (The file must contain a RecNum column and it must be first)&lt;br /&gt;
**1+ - Any positive number means Update by that Key (as listed in the layout).&lt;br /&gt;
&lt;br /&gt;
==== fnCSVExport ====&lt;br /&gt;
&lt;br /&gt;
This function exports a data file to a CSV file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCsvExport(Layout$*64;SuppressDialog,Filename$*300,IncludeRecNums,KeyNumber,StartKey$,KeyMatch$,Startrec,mat Records,SearchMatch$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The File Layout to Export&lt;br /&gt;
*SuppressDialog - (1 to Suppress the Export Dialog, 0 to show it)&lt;br /&gt;
*Filename$ - the output file name (Required if SuppressDialog is 1)&lt;br /&gt;
*IncludeRecNums - Include a column with the Record Numbers in it&lt;br /&gt;
*KeyNumber - Use this key when reading the data for export&lt;br /&gt;
*StartKey$ - Start with the record that matches StartKey$&lt;br /&gt;
*KeyMatch$ - Export only the record(s) that match KeyMatch$&lt;br /&gt;
*StartRec - Start with this Record Number&lt;br /&gt;
*mat Records - Export only these records&lt;br /&gt;
*SearchMatch$ - Export only records containing this search string anywhere in them&lt;br /&gt;
&lt;br /&gt;
==== fnGenerateLayout &amp;amp; fnWriteLayout ====&lt;br /&gt;
&lt;br /&gt;
This function calls on the Generate File Layout Wizard to generate and save the layout indicated by the parameters you give it. You must give it the same valid parameters that you would have come up with if you worked through the layout wizard the normal way, by running FileIO directly and choosing &amp;quot;Generate Layout&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can also bypass the automatic parsing and generate a layout by specifying all the data directly and using fnWriteLayout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnGenerateLayout(mat OpenStrings$, ReadString$*999, FormString$*20000, DimString$*999; DisplayFile)&#039;&#039;&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat OpenString$ - array of all the open strings for the given file from one of your old programs.&lt;br /&gt;
*mat ReadString$ - solid read statement from one of your old programs reading the entire record, (or at least everything you want in the layout).&lt;br /&gt;
*mat FormString$ - the form statement that goes with the ReadString$ (practice using the Generate Layout Wizard the normal way for details)&lt;br /&gt;
*mat DimString$ - the string containing Dim statements for each array mentioned in ReadString$. We need this to know how big the arrays are.&lt;br /&gt;
*DisplayFile - if True (1), it will Display the new layout in notepad when its done creating it. If false (0), it will simply create the file.&lt;br /&gt;
&lt;br /&gt;
fnGenerateLayout takes all the above information and parses it into a layout, then calls fnWriteLayout to actually write the layout.&lt;br /&gt;
&lt;br /&gt;
If you already know the information you want to put in the layout, its more direct to call fnWriteLayout below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnWriteLayout(Name$,FileName$*127,VER,PRE$,MAT KFNAME$,MAT KDESCRIPTION$,MAT SUBS$,MAT DESCR$,MAT FORM$;RECL,MAT EXTRA$,DISPLAYFILE)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Name$ - the name of the new layout&lt;br /&gt;
*FileName$*127 - the name of the data file&lt;br /&gt;
*Ver - the version of the data file&lt;br /&gt;
*Pre$ - the prefix to use for the data file&lt;br /&gt;
*mat KfName$ - array of all the keys for the file&lt;br /&gt;
*mat Kdescription$ - array of the subscripts that each key is based on&lt;br /&gt;
*mat Subs$ - the subscript for each field in the file&lt;br /&gt;
*mat Descr$ - the descriptions for each field in the file&lt;br /&gt;
*mat Form$ - the form specs for each field in the file&lt;br /&gt;
*Recl - (optional) the record length of the file&lt;br /&gt;
*mat Extra$ - (optional) Additonal Information for each field in the file, placed in the Comments column of the new layout. This column is ignored by standard fileio processing.&lt;br /&gt;
DisplayFile - if True, open the file in Notepad after it has been created.&lt;br /&gt;
&lt;br /&gt;
=== File System Utility Functions ===&lt;br /&gt;
These functions perform other tasks that aid with interacting with the file system.&lt;br /&gt;
&lt;br /&gt;
==== fnGetFileDateTime$ ====&lt;br /&gt;
This does a directory listing to determine the Last Modified Date and Time of the given file. You pass it a file name, not a file layout, and it can be used on any file. Its not limited to BR internal files.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let FileDate$=fnGetFileDateTime$(Filename$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnCopyFile ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCopyFile(FromFile$*255,ToFile$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FromFile$ - The file to copy.&lt;br /&gt;
*ToFile$ - The destination file name including path.&lt;br /&gt;
&lt;br /&gt;
This function copies any file, by opening it as an external file and reading and writing the data to the destination file. The advantage of this technique, over using the BR copy command, is this routine is more reliable when run on client server where you may be transferring large files from one side to the other over the internet.&lt;br /&gt;
&lt;br /&gt;
This fnCopyFile also has a progress bar that displays as the file is transferred, so the user knows your software is busy.&lt;br /&gt;
&lt;br /&gt;
This function works over Client Server. Under Client Server, specify @: at the beginning of your filename, to specify that the file is on the client. If the file is on the server, simply leave the @: off. See the chapter on [[Copy#Client_Server|using BR&#039;s copy command under Client Server]] for more details on the &amp;quot;@:&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This function&#039;s parameters and syntax are modeled off of the built in BR copy command, and like that one, this should work for local transfers, LAN transfers, or even internet transfers. This function will work better for internet transfers then the built in BR Copy Command, however. &lt;br /&gt;
&lt;br /&gt;
==== fnCopyDataFiles ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnCopyDataFiles(DestinationFolder$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*DestinationFolder$ - the folder to copy your data files to.&lt;br /&gt;
&lt;br /&gt;
This function reads your file layouts and makes a copy of every data file (and key file) in your system to the destination folder, utilizing fnCopyFile above, for better performance and reliability when running over the internet, as well as a progress bar for each individual file.&lt;br /&gt;
&lt;br /&gt;
It also displays a listview while its copying so you can watch the progress while its transferring your data files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This can be used for making backups of your BR data, or for transferring the latest data onto a laptop for access to it while you&#039;re on the road away from the internet.&lt;br /&gt;
&lt;br /&gt;
==== fnReIndex ====&lt;br /&gt;
&lt;br /&gt;
This function reindexes a single data file&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReIndex(DataFile$*255;CallingProgram$*255,IndexNum,Path$*25)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Datafile$ - the file layout of the file to index&lt;br /&gt;
*CallingProgram$ - used for logging, pass Program$ in here&lt;br /&gt;
*IndexNum - The index to rebuild - if not given, rebuilds all indexes&lt;br /&gt;
*Path$ - the optional alternate path to use for rebuilding the data file.&lt;br /&gt;
&lt;br /&gt;
==== fnReIndexAllFiles ====&lt;br /&gt;
&lt;br /&gt;
This function reindexes all your data files. It doesn&#039;t require any parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReIndexAllFiles&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnUpdateFile ====&lt;br /&gt;
This function checks and Updates a data file if it needs to be updated, by opening and then closing the data file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnUpdateFile(FileLayout$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*FileLayout$ - The name of the file to update&lt;br /&gt;
&lt;br /&gt;
==== fnRemoveDeletes ====&lt;br /&gt;
&lt;br /&gt;
This function, written by Susan Smith, removes deleted records by copying the file with the -D option.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnRemoveDeletes(LayoutName$*255;Path$*255,CallingProgram$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*LayoutName$ - the file layout&lt;br /&gt;
*Path$ - Optional Alternate Path&lt;br /&gt;
*CallingPRogram$ - used for logging, pass Program$ in here&lt;br /&gt;
&lt;br /&gt;
=== Layout Interrogation ===&lt;br /&gt;
Layout interrogation functions are provided for convenience and to enable future dictionary changes without disrupting any programs that interrogate it.&lt;br /&gt;
&lt;br /&gt;
==== fnMakeSubProc ====&lt;br /&gt;
This function obtains the subscript assignments that were assigned by fnOpen according to the file layout. The fnMakeSubProc$ routine obtains the subscript assignments without actually opening the file. This is useful when a file record is passed as arrays into a library function in another program, or when you chained to another program and you need to know how to reach the data in the arrays without actually reopening the file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnMakeSubProc(filelay$;mat Subscripts$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*FileLay$ - The name of the file layout from which to read the subscripts.&lt;br /&gt;
*mat Subscripts$ - If you give this optional array, fnMakeSubProc passes the subscripts back in this array rather then in the subs.$$$ file. This is much faster and helps avoid sharing conflicts.&lt;br /&gt;
&lt;br /&gt;
When this routine returns, you can set the subscripts in your program by executing every element of the Subscripts$ array in a for/next loop.&lt;br /&gt;
&lt;br /&gt;
If you did not pass in a subscripts array, then the a procedure file named subs.$$$ is created. If you proc that file, the proper subscripts will be set.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutArrays ====&lt;br /&gt;
This function reads the fields in a file layout into arrays. You call it like the following&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLayoutArrays(filelay$,&amp;amp;prefix$;mat SSubs$, mat NSubs$, mat SSpec$, mat NSpec$,mat SDescription$, mat NDescription$,Mat Spos,Mat Npos)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*filelay$ - the name of the layout to read&lt;br /&gt;
*prefix$ - the return value for the prefix for the file&lt;br /&gt;
*mat SSubs$ - the return value for all the string subscripts in the layout&lt;br /&gt;
*mat NSubs$ - the return value for the numeric subscripts in the layout&lt;br /&gt;
*mat SSpec$ - the return value for the string fields specs&lt;br /&gt;
*mat NSpec$ - the return value for the numeric fields specs&lt;br /&gt;
*mat SDescription$ - the return value for the Descriptions of the String Specs&lt;br /&gt;
*mat NDescription$ - the return value for the Descriptions of the Numeric Specs&lt;br /&gt;
*mat SPos - the return value for the starting positions of the String Specs&lt;br /&gt;
*mat NPos - the return value for the starting positions of the Numeric Specs&lt;br /&gt;
&lt;br /&gt;
This function call would read the fields from the layout in filelay$, and it would return the prefix to prefix$. The Subs would be returned in mat SSubs$ and mat NSubs$.&lt;br /&gt;
&lt;br /&gt;
The Spec statements are returned in mat SSpec$ and mat NSpec$ and the Descriptions are returned in mat SDescription$ and mat NDescription$. The start positions on disk of each element are returned in mat SPos and mat NPos.&lt;br /&gt;
&lt;br /&gt;
All the arrays are optional. If you don’t pass them the information they are supposed to record is simply not returned.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutHeader ====&lt;br /&gt;
This function reads the header for a given file layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLayoutHeader(Layoutname$*255;&amp;amp;Filename$,Mat Keys$,Mat KeyDescription$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*LayoutName$ - Name of the layout to read&lt;br /&gt;
*Filename$ - The file name read from the layout&lt;br /&gt;
*Mat Keys$ - Array to be populated with the list of keys for the file&lt;br /&gt;
*Mat KeyDescription$ - Key Description String returned from the file&lt;br /&gt;
&lt;br /&gt;
==== fnReadEntireLayout ====&lt;br /&gt;
This function reads the entire layout by calling fnReadLayoutHeader and fnReadLayoutArrays.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadEntireLayout(Layoutname$*255;&amp;amp;Filename$,&amp;amp;Prefix$,Mat Keys$,Mat KeyDescription$,Mat Ssubs$,Mat Nsubs$,Mat Sspec$,Mat Nspec$,Mat Sdescription$,Mat Ndescription$,Mat Spos,Mat Npos)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*LayoutName$ - Name of the layout to read&lt;br /&gt;
*Filename$ - The file name read from the layout&lt;br /&gt;
*prefix$ - the return value for the prefix for the file&lt;br /&gt;
*Mat Keys$ - Array to be populated with the list of keys for the file&lt;br /&gt;
*Mat KeyDescription$ - Key Description String returned from the file&lt;br /&gt;
*mat SSubs$ - the return value for all the string subscripts in the layout&lt;br /&gt;
*mat NSubs$ - the return value for the numeric subscripts in the layout&lt;br /&gt;
*mat SSpec$ - the return value for the string fields specs&lt;br /&gt;
*mat NSpec$ - the return value for the numeric fields specs&lt;br /&gt;
*mat SDescription$ - the return value for the Descriptions of the String Specs&lt;br /&gt;
*mat NDescription$ - the return value for the Descriptions of the Numeric Specs&lt;br /&gt;
*mat SPos - the return value for the starting positions of the String Specs&lt;br /&gt;
*mat NPos - the return value for the starting positions of the Numeric Specs&lt;br /&gt;
&lt;br /&gt;
==== fnReadSubs ====&lt;br /&gt;
This function reads the subscripts from a layout into Subs arrays.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadSubs(Layout$,mat SSubs$,mat NSubs$,&amp;amp;Prefix$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - the file layout name&lt;br /&gt;
*mat SSubs$ - the String Subscript Names&lt;br /&gt;
*mat NSubs$ - the Number Subscript Names&lt;br /&gt;
*Prefix$ - the files Prefix&lt;br /&gt;
&lt;br /&gt;
==== fnReadKeyFiles ====&lt;br /&gt;
This function reads the list of key files from the layout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadKeyFiles(Layout$,mat Keys$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - The file layout&lt;br /&gt;
*mat Keys$ - output array, the keys are returned here.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayouts ====&lt;br /&gt;
This function reads the file layout folder and returns all the applicable layouts in the passed in array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnReadLayouts(mat Dirlist$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Mat Dirlist$ - After running the function, mat Dirlist$ will contain a list of all the file layouts that FileIO can find.&lt;br /&gt;
&lt;br /&gt;
==== fnReadLayoutPath$ ====&lt;br /&gt;
This function doesn&#039;t actually interrogate your layouts. Instead, it interrogates your settings and returns the path specified for your layout files. This would usually be &amp;quot;filelay\&amp;quot; but you can change it in [[#fnSettings|fileio.ini.]]&lt;br /&gt;
&lt;br /&gt;
It has no parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let Path$=fnReadLayoutPath$&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnDoesLayoutExist ====&lt;br /&gt;
This function returns true if the given file layout exists. It returns false if the layout does not exist.&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;FnDoesLayoutExist(layout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Layout$ - Layout to test for&lt;br /&gt;
&lt;br /&gt;
==== fnReadForm$ (uncompiled) ====&lt;br /&gt;
Sometimes you need to know the original form statement that fileio is using to read your data file, most often when you&#039;re debugging your file layout, and you&#039;re getting some problem when reading the file. The form statement that fileio normally returns is compiled using CFORM$ to save space in the array, and to make the execution of your read statements faster. You can use this function to return the original form statement for the file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let FormStatement$=fnReadForm$*10000(FileLayout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remember to dimension FormStatement to something huge! fnReadForm$ can return up to 10,000 characters.&lt;br /&gt;
&lt;br /&gt;
==== fnReadFormAndSubs ====&lt;br /&gt;
&lt;br /&gt;
This function does the same as above but it also reads the subscripts from the file into an array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;let fnReadFormAndSubs(Layout$,mat Subs$,&amp;amp;ReadForm$,&amp;amp;StringSize,&amp;amp;NumberSize)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note that unlike most of our functions, all the above parameters are required.&lt;br /&gt;
&lt;br /&gt;
The layout is the layout you&#039;re interrogating. The Array will be populated with the subscripts after the function. The ReadForm$ variable will be filled with the form statement for the file. Remember to dimension it large enough. StringSize and NumberSize will contain the number of string fields and numeric fields in the file.&lt;br /&gt;
&lt;br /&gt;
Mat Subs$ will be returned, strings first, numbers last, matching the form statement that is returned. So Subs$(1) is the first string subscript and Subs$(StringSize+1) is the first Numeric subscript.&lt;br /&gt;
&lt;br /&gt;
=== Other Useful Functions (non-layout related) ===&lt;br /&gt;
&lt;br /&gt;
==== fnAskCombo ====&lt;br /&gt;
&lt;br /&gt;
Opens a window with a combo box and returns the users selection.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnAskCombo$*255(mat Description$;Caption$*60,Default$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Description$ - contains the combo box choices&lt;br /&gt;
*Caption$ - contains the optional caption for the window&lt;br /&gt;
*Default$ - the text of the item in mat Description$ that you want to be selected by default&lt;br /&gt;
&lt;br /&gt;
==== fnSendEmail ====&lt;br /&gt;
&lt;br /&gt;
This function sends an email and an optional attachment to the email address specified.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnSendEmail(Emailaddress$*255,Message$*10000;Subject$*255,Invoicefile$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*EmailAddress$ - the Destination Email Address&lt;br /&gt;
*Message$ - the Message$ to send&lt;br /&gt;
*Subject$ - the subject&lt;br /&gt;
*InvoiceFile$ - the filename of a file to attach. This is the BR filename (the function automatically converts it to an OS Filename.)&lt;br /&gt;
&lt;br /&gt;
The function returns 1 when the email was sent successfully, or 0 if it wasn&#039;t sent successfully.&lt;br /&gt;
&lt;br /&gt;
In order to use this function, you must have the emailcfg file layout in your layouts folder and you must have a copy of SendEmail.exe which is free and can be downloaded from the internet. Both of these files are included with the latest update of fileio.&lt;br /&gt;
&lt;br /&gt;
You also have to configure fileio with the authentication information for your email server.&lt;br /&gt;
&lt;br /&gt;
To configure your email server, simply run FileIO to get the data crawler, then select the emailcfg file layout and press F5 to edit it. Add a row if the file is empty.&lt;br /&gt;
&lt;br /&gt;
Simply fill in the information the file is asking for in the appropriate fields and save the data, and then test sending an email to make sure it worked.&lt;br /&gt;
&lt;br /&gt;
==== fnClientEnv$ ====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a Windows Environment Variable on the client under Client Server.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnClientEnv$*255(EnvKey$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*EnvKey$ is the name of the Windows Environment Variable to check on the client.&lt;br /&gt;
&lt;br /&gt;
The function returns the value of the entered environment variable.&lt;br /&gt;
&lt;br /&gt;
==== fnEmpty &amp;amp; fnEmptyS ====&lt;br /&gt;
These functions are for testing optional arrays that may or may not have been passed into your function. BR will give an error if your code attempts to use an optional array that wasn&#039;t passed in, so you can use these functions to test if the user actually passed in the optional array or not.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnEmpty(mat Numeric)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnEmptyS(mat String$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  def fnSomeFunction(String$,mat Array$; mat OptionalArray)&lt;br /&gt;
     if ~fnEmpty(mat OptionalArray) then&lt;br /&gt;
        ! mat Optional array was given, process it here.&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
==== fnReadScreenSize ====&lt;br /&gt;
This function reads the screen size of the given window (or window 0 if a window wasn&#039;t passed.) This is useful for centering a window on the screen, or for making sure window 0 is big enough for the child window you&#039;re trying to create.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadScreenSize(&amp;amp;Rows,&amp;amp;Cols;ParentWindow)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The screen size is returned in the first two parameters, and the third parameter tells the function which window to interrogate. If not given, it assumes window 0.&lt;br /&gt;
&lt;br /&gt;
==== fnBuildProcFile ====&lt;br /&gt;
This function builds a proc file to be executed later. This function and the next simplify the process of executing code in a proc file. It can even be used to spawn a new session of BR.&lt;br /&gt;
&lt;br /&gt;
To use it, call fnBuildProcFile one or more times and specify some lines of code to execute.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnBuildProcFile(Command$*255)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;load Program2$&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;run&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;system&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  let fnRunProcFile(1)&lt;br /&gt;
&lt;br /&gt;
==== fnRunProcFile ====&lt;br /&gt;
&lt;br /&gt;
This function spawns a new copy of BR and in it, runs the proc file that you&#039;ve previously built using fnBuildProcFile (above).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; fnRunProcFile(;NoWait) &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The optional parameter &amp;quot;NoWait&amp;quot; causes the other session to spawn and run in a new thread. If you don&#039;t specify NoWait, the current session pauses and waits for the other session to close before proceeding.&lt;br /&gt;
&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;load Program2$&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;run&amp;quot;)&lt;br /&gt;
  let fnBuildProcFile(&amp;quot;system&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
  let fnRunProcFile(1)&lt;br /&gt;
&lt;br /&gt;
==== fnLog &amp;amp; fnErrLog ====&lt;br /&gt;
These next two functions are functions to aid in logging. When you call either of these two functions, you give them a string that you wish to log. They will open the FileIO Log File and add a record to the end of it containing some user information such as login_name and session$, and the string that you specified. FnErrLog does the same thing as fnLog except it also logs the Error Number and the Line.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnLog(string$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - the Log Message&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FnErrLog(String$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*String$ - the Log Message&lt;br /&gt;
&lt;br /&gt;
==== fnLogArray ====&lt;br /&gt;
&lt;br /&gt;
This function logs the given arrays to the log file, logging each field in the arrays. Its useful for recording, for example, an entire data record that is about to be written to a data file.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnLogarray(mat F$,mat f;Message$*512,CallingProgram$*255)&#039;&#039;&lt;br /&gt;
The first two parameters, of course, are the array to log. The third parameter is an optional message to be recorded along with the array, and the fourth optional parameter is the CallingProgram$ to save in the log along with the message. (The CallingProgram$ parameter can usually be passed as the system function Program$)&lt;br /&gt;
&lt;br /&gt;
==== fnSetLogChanges ====&lt;br /&gt;
This function works in conjunction with the next function, and they&#039;re for recording just what changed in a data file. When the file is read, you call fnSetLogChanges and record the &amp;quot;before&amp;quot; picture of the file record.&lt;br /&gt;
&lt;br /&gt;
After changes have been made and saved back to disk, you can call fnLogChanges below to record the actual changes.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnSetLogChanges(mat F$,mat F)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnLogChanges ====&lt;br /&gt;
This function is the other half of the function above. It compares the given arrays with the ones set previously in the above function and checks for changes. Then it generates a log message recording information about just the items that changed.&lt;br /&gt;
&lt;br /&gt;
The syntax is:&lt;br /&gt;
&#039;&#039;fnLogChanges(mat F$,mat F;Message$*1024,CallingProgram$*255,Layout$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You need to pass in the same two arrays as before, but this time the modified versions of them.&lt;br /&gt;
&lt;br /&gt;
You can also optionally pass a 1024 byte log message to record with the log entry.&lt;br /&gt;
&lt;br /&gt;
CallingProgram$ again should be passed as the system internal function Program$.&lt;br /&gt;
&lt;br /&gt;
The final parameter allows the passing of a Layout$. If you pass a Layout$, that layout is read and the subscripts are used when making the log message of changes, so that its easier to read. If you pass a layout, it will identify the changed fields by name. If you don&#039;t it will identify those fields by relative position number.&lt;br /&gt;
&lt;br /&gt;
==== fnViewLogFile ====&lt;br /&gt;
All of the above functions store the information by default into a BR internal file defined in the filelay\logfile layout.&lt;br /&gt;
&lt;br /&gt;
The fnViewLog function uses fnShowData to call the Data Crawler to display the FileIO Log File in a searchable listview.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnViewLogFile&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== fnReadLockedUsers ====&lt;br /&gt;
&lt;br /&gt;
This function returns a list of all users using the locked data file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnReadLockedUsers(mat Users$)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*mat Users$ - the list of users is returned here&lt;br /&gt;
&lt;br /&gt;
==== fnDisplayLength ====&lt;br /&gt;
This function calculates the display length of a field based on its form spec.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnDisplayLength(Spec$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Spec - the Form Spec to return the display length of.&lt;br /&gt;
&lt;br /&gt;
==== fnLength ====&lt;br /&gt;
This function calculates the length on disk of a field based on its form spec.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;fnLength(Spec$)&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Spec$ - the Form Spec to return the display length of.&lt;br /&gt;
&lt;br /&gt;
== FileIO fnSettings (Global Settings Code) ==&lt;br /&gt;
&lt;br /&gt;
The FileIO library can be made to implement certain policies across the board.  These are established by creating a file called fileio.ini and typing statements like the following into it. This file is &amp;quot;PROCed&amp;quot;, so you don&#039;t want to put line numbers in it.&lt;br /&gt;
&lt;br /&gt;
Anything you don&#039;t specify in fileio.ini will take its default value, shown below. So you only need to specify the items that you want to be different.&lt;br /&gt;
&lt;br /&gt;
Note, for the boolean settings below, 1 denotes TRUE and 0 denotes FALSE.&lt;br /&gt;
&lt;br /&gt;
  let EnforceDupkeys=1                   ! Enforce that key number 1 is unique key&lt;br /&gt;
  let Defaultfilelayoutpath$=&amp;quot;filelay\&amp;quot;  ! Path To Your File Layouts&lt;br /&gt;
  let Promptonfilecreate=1               ! Ask User Before Creating New Files&lt;br /&gt;
  let Createlogfile=0                    ! Use Logging&lt;br /&gt;
  let StartFileNumber=1                  ! Set above 300 to avoid conflicts with legacy programs.&lt;br /&gt;
  let CheckIndex=0                       ! Automatically Verify Indexes (slow)&lt;br /&gt;
  let CompressColumns=0                  ! Shrink or Expand Columns in Data Crawler by Default&lt;br /&gt;
  let MaxColWidth=20                     ! Max Default Column Width in Data Crawler&lt;br /&gt;
  let LogLibrary$=&amp;quot;&amp;quot;                     ! Defaut Log Library, defaults to None&lt;br /&gt;
  let LogLayout$=&amp;quot;&amp;quot;                      ! Log file layout, defaults to Internal File&lt;br /&gt;
  let AnimateDatacrawler=1               ! Use ScreenIO Animation for Datacrawler&lt;br /&gt;
  let TemplatePath$=&amp;quot;filelay\template\&amp;quot;  ! Default Template Path&lt;br /&gt;
  let IgnoreLayouts$=&amp;quot;&amp;quot;                  ! List any Ignore Layouts here.&lt;br /&gt;
  let CloseFileSimple=0                  ! Use simple comparison for fnCloseFile&lt;br /&gt;
&lt;br /&gt;
==== EnforceDupkeys ====&lt;br /&gt;
&lt;br /&gt;
Turn on the EnforceDupkeys option to force that the first key listed in your file layouts is a unique key. FileIO will generate the standard BR error for Dupkeys when attempting to create indexes if it is not unique.&lt;br /&gt;
&lt;br /&gt;
==== DefaultFileLayoutPath$ ====&lt;br /&gt;
&lt;br /&gt;
Use the DefaultFileLayoutPath option to specify the path from your programs to your file layout folder. The default is &amp;quot;filelay\&amp;quot;. Use this setting if you want to place your file layouts in another folder from the default.&lt;br /&gt;
&lt;br /&gt;
==== PromptOnFileCreate ====&lt;br /&gt;
&lt;br /&gt;
Use the PromptOnFileCreate setting to cause FileIO to display a message box whenever it is attempting to create a new file. This happens during the automatic update procedure, as well as during any attempt to access a file that does not exist. This setting should be turned off in your live system, and only turned on for development purposes. If you use the message box to cancel creating of the new file, then the file is not created, and fileIO or your application will most likely give an error when you attempt to actually access the new file.&lt;br /&gt;
&lt;br /&gt;
It can be useful during development to make sure that you don&#039;t accidentally create the wrong files, due to an incorrectly specified path or a typeo in the filename in the layout file. However, in a live system, these things have already been tested, and you generally want the default behavior, because you don&#039;t want your users to have the ability to cancel the normal operation of FileIO.&lt;br /&gt;
&lt;br /&gt;
==== CreateLogFile ====&lt;br /&gt;
&lt;br /&gt;
Use this option to specify weather or not to use the FileIO log file. If it is turned on, a log file called FileIO.log in the current directory is created with entries listing all attempts to open a file, automatically update one, or automatically update your indexes.&lt;br /&gt;
&lt;br /&gt;
==== StartFileNumber ====&lt;br /&gt;
&lt;br /&gt;
Use this option to set the starting file number that the fnGetFileNumber and the fnOpen functions use to search for available file numbers. This is so that if you have certian reserved file numbers in your code, you can make sure that FileIO will not use those reserved file numbers, causing a conflict with your already existing programs. The default is 1, which is fine if your software does not have any reserved file numbers.&lt;br /&gt;
&lt;br /&gt;
The allowable BR file numbers are 1-200 and 300-999.&lt;br /&gt;
&lt;br /&gt;
==== CheckIndex ====&lt;br /&gt;
&lt;br /&gt;
This function is used for Partial FileIO Implementations. If all of your software uses FileIO then all of your indexes are kept automatically up to date by the FileIO library and BR&#039;s internal file processing systems. However, if some of your programs do not use FileIO, and you use the FileIO library to add a new index file that those other programs do not know about, then its possible for the additional index file to become out of date when the master file is updated by your other programs.&lt;br /&gt;
&lt;br /&gt;
Use this setting to cause FileIO to check the DateTime stamp on all your index files when opening a new file, and automatically update any indexes that may have potentially gotten out of date from other programs.&lt;br /&gt;
&lt;br /&gt;
This option slows down the processing of the fnOpen function, particularly when running under client server over the internet. If you know that every program in your application suite uses FileIO, and that any programs that do not use FileIO still properly update all the indexes that your data file uses, then you can safely leave this setting turned off, and optimize your performance when opening several files using the fileIO system.&lt;br /&gt;
&lt;br /&gt;
==== CompressColumns ====&lt;br /&gt;
This instructs the datacrawler to use smaller widths for small columns. If CompressColumns is false, the data crawler will make the column the width of the field or the width of the caption, whichever is wider. If CompressColumns is true, it will use the width of the field, not the caption.&lt;br /&gt;
&lt;br /&gt;
==== MaxColWidth ====&lt;br /&gt;
This limits the column width to a set amount. This is applied after CompressColumns above.&lt;br /&gt;
&lt;br /&gt;
==== LogLibrary$ ====&lt;br /&gt;
If a library is specified here, then fileio looks for a BR library with the specified name, and attempts to call a library function in it called fnFileIOLog that. This function should expect six parameters, which are Logstring$, Login_Name$, Session$, Days of Date$, Time$, and CallingProgram$, if LogLayout is also nonblank.&lt;br /&gt;
&lt;br /&gt;
If you specify a LogLibrary and LogLayout is blank, then it calls your function giving it only 1 parameter.&lt;br /&gt;
&lt;br /&gt;
It will call your function &#039;&#039;&#039;&#039;&#039;instead of&#039;&#039;&#039;&#039;&#039; the normal log file. Use this to implement your own logging functions however you want.&lt;br /&gt;
&lt;br /&gt;
==== LogLayout$ ====&lt;br /&gt;
Use this setting to specify an alternate file layout for an alternate file to do the logging in. Base the file layout for this file on the logfile we supply for you in the filelay folder. It should have at least those fields, which our log routine will automatically populate, but you can add other fields if you want (though you will need to manage them yourself).&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t specify LogLayout, the default filelay\logfile will be used. This will allow you to also use the fnViewLogFile function to access it.&lt;br /&gt;
&lt;br /&gt;
==== AnimateDataCrawler ====&lt;br /&gt;
The sister library [[ScreenIO]] has a feature that allows you to use an animation of a clock in your loading screens in your own programs. If you have [[ScreenIO]] then FileIO will automatically detect it and use it to display a loading animation while the data in the data crawler loads.&lt;br /&gt;
&lt;br /&gt;
Set AnimateDataCrawler to false (0) in your fileio.ini file to bypass the animations if you do have screenio but don&#039;t want to see the animations anyway.&lt;br /&gt;
&lt;br /&gt;
==== TemplatePath$ ====&lt;br /&gt;
This setting points to the folder that contains the code templates used by the Generate Code button on the main page of the Data Crawler.&lt;br /&gt;
&lt;br /&gt;
==== IgnoreLayouts$ ====&lt;br /&gt;
This is a comma delimited list of all layouts that you wish to suppress from appearing on the main page of the data crawler. You can still access these layouts with your code, but they won&#039;t be listed in the data crawler for you to access.&lt;br /&gt;
&lt;br /&gt;
Whatever you&#039;re using for a log layout, is automatically added to this list.&lt;br /&gt;
==== CloseFileSimple ====&lt;br /&gt;
The fnCloseFile function closes all the individual handles to a data file that was opened for output using multiple keys.&lt;br /&gt;
&lt;br /&gt;
For BR 4.18 and higher, we support a better algorithm for detecting which files are matches for a given opened file number.&lt;br /&gt;
&lt;br /&gt;
Set CloseFileSimple to true (1) to force it to check the old way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== FileIO Add-on Packages ==&lt;br /&gt;
&lt;br /&gt;
Many FileIO Add-on packages are currently in the works.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Library ===&lt;br /&gt;
&lt;br /&gt;
The [[ScreenIO Library]] is a sister library to the FileIO library. The ScreenIO library requires the FileIO library in order to run.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO library is a complete Rapid Application Design tool that enables you to implement custom screen functions anywhere in your exiting programs.&lt;br /&gt;
&lt;br /&gt;
If you call the ScreenIO Library as a function library, you call a function called fnFM and tell it which screen you wish to use. The ScreenIO library loads your user interface, loads your data files, and preforms all the file maintenance operations you have designed into your screens.&lt;br /&gt;
&lt;br /&gt;
You can find out the latest information about the ScreenIO library in the ScreenIO page.&lt;br /&gt;
&lt;br /&gt;
=== Audit BR ===&lt;br /&gt;
&lt;br /&gt;
The [[AuditBR|Audit BR]] developer tool makes a backup copy of your file layouts. Then you run some code you&#039;re trying to test, and finally, run Audit BR again, to get a report showing all the changes to any of your data files automatically.&lt;br /&gt;
&lt;br /&gt;
== What’s New (also described above) ==&lt;br /&gt;
=== 2018 ===&lt;br /&gt;
*Support for dates in any storage formats on disk (v2.48)&lt;br /&gt;
&lt;br /&gt;
=== 2015 ===&lt;br /&gt;
*Added Rec to display for fnShowData&lt;br /&gt;
*Added FormStatement$ for debugging of form statements inside fileio&lt;br /&gt;
*Added mat BadRead$ for debugging of 726 errors when making new layouts&lt;br /&gt;
*Fixed a bug causing crash when logging things from long program folders&lt;br /&gt;
*fnClientEnv$ - reads a Windows Environment variable on the client using the command shell&lt;br /&gt;
*fnAskCombo$ - added an optional parameter to set default selection.&lt;br /&gt;
&lt;br /&gt;
=== 2010 - 2014 ===&lt;br /&gt;
*FileIO now caches your file layouts in memory to make it much faster then before when opening the same data file in multiple programs.&lt;br /&gt;
*Generate Layout Wizard&lt;br /&gt;
*fnShowData&lt;br /&gt;
*Improved Logging&lt;br /&gt;
*fnViewLogFile&lt;br /&gt;
*Import/Export&lt;br /&gt;
*Import/Export by Function&lt;br /&gt;
*Many other speed increases&lt;br /&gt;
*if ScreenIO is present, Datacrawler uses the animation routines&lt;br /&gt;
*fnBuildProcFile &amp;amp; fnRunProcFile&lt;br /&gt;
*fnGenerateLayout &amp;amp; fnWriteLayout&lt;br /&gt;
*fnReadForm$&lt;br /&gt;
*fnReadFormAndSubs&lt;br /&gt;
*fnGetFileDateTime$&lt;br /&gt;
*fnReadLayoutPath$&lt;br /&gt;
*fnSortKeys&lt;br /&gt;
*fnSetLogChanges&lt;br /&gt;
*fnLogChanges&lt;br /&gt;
*fnLogArray&lt;br /&gt;
*fnReadScreenSize&lt;br /&gt;
*fnEmpty&lt;br /&gt;
*fnEmptyS&lt;br /&gt;
*Many other useful functions that were added to the documentation at earlier dates.&lt;br /&gt;
&lt;br /&gt;
=== Spring 2009 ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;New Functions:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The FileIO Library has been updated in Spring 2009 to provide several new functions:&lt;br /&gt;
&lt;br /&gt;
*fnReadRecordWhere&lt;br /&gt;
*fnKey$&lt;br /&gt;
*fnBuildKey$&lt;br /&gt;
*fnReadUnopenedDescription$&lt;br /&gt;
*fnUpdateFile&lt;br /&gt;
*fnDisplayLength&lt;br /&gt;
*fnLength&lt;br /&gt;
*fnReadLayoutHeader&lt;br /&gt;
*fnReadEntireLayout&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Speed Increases:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Thanks to the BR [[Profiler]], we have increased the speed of FileIO fnOpen function by ten times when running over a LAN and by 100 times when running over the internet using Client Server.&lt;br /&gt;
&lt;br /&gt;
In order to get the new Speed Upgrades, you will need to make sure that you use the latest copy of the [[#fnOpen_Function|fnOpen]] function in each one of your programs that use FileIO.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Network FileIO:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
This version of FileIO has been optimized to work better in network situations.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;FnSettings: &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
There are more configuration options in the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] routine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Automatic Update Speed Fix:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The automatic update proceedure has been made to run more then 100 times faster then before according to our benchmarking tests.&lt;br /&gt;
&lt;br /&gt;
=== Fall 2008 ===&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;DataCrawler Grid:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
By popular request we added a read/write version to the data crawler. This version works exactly the same as the datacrawler did before but it displays all the contents of your data files in a grid instead of a listview. &lt;br /&gt;
&lt;br /&gt;
When you run the fileIO library as a program, it launches a tool known as the [[#DataCrawler|DataCrawler]]. The DataCrawler shows a listview displaying all your layout files in it. If you select one, it builds another listview with all the data in your selected data file.&lt;br /&gt;
&lt;br /&gt;
If you are looking at the first list of all your file layouts, and you press F5, a grid will be build displaying all the data in your data files. You can change any of the records you like, and when you&#039;re done, your changes will be saved to the data file. Additionally, you can Add or Delete records using the buttons at the bottom. Any changes you make are not written to the disk until you click the &amp;quot;Save&amp;quot; button. If you press ESC (Cancel) the grid is closed and all changes you made sinse the last save are lost.&lt;br /&gt;
&lt;br /&gt;
This tool is for programmers only. Do not give your end users access to the DataCrawler.&lt;br /&gt;
&lt;br /&gt;
Use the DataCrawler at your own risk. Gabriel Bakker and Sage AX are not responsible for any harm that comes to your data files through the use of this or any other tools we offer.&lt;br /&gt;
&lt;br /&gt;
The DataCrawler is not designed to be used to maintain your data files. It can be used carefully to correct small things in your data files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Support for Nonstandard Paths:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Many BR Vendors keep different versions of the same data files in different locations. For example, sometimes a BR vendor will use a different Data folder to represent data for different Warehouses, or Customers. In cases like this it is necessary for your programs to specify the path to your data files. They may do so by specifying the optional &amp;quot;PATH&amp;quot; parameter to your data files. See the section [[#fnOpenFile]] for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Support for Nonstandard Layout Files Path:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Old versions of the fileIO library required you to place all your file layouts in a subfolder of your program directory called &amp;quot;filelay&amp;quot;. We have now changed the Fileio library to allow you to place your file layouts any place you want. The only requirement is that they are all together in one folder by themselves.&lt;br /&gt;
&lt;br /&gt;
If you use a nonstandard path in the fileIO library, it is necessary to make a change to the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] code in your copy of fileio.br.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Prompt on Create:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The FileIO library automatically creates any data files that it can&#039;t find. This was done to make it easier to deploy your finished programs - if you had any empty data files you could omit them from the packages and they would be created when they were needed, on the fly.&lt;br /&gt;
&lt;br /&gt;
The current version of the FileIO library contains the same ability. However, it prompts you before creating any data files. This helps to avoid bugs that happen from incorrectly specifying the path to your data files.&lt;br /&gt;
&lt;br /&gt;
However, if you do intend for your data files to be autocreated, then you probably don&#039;t want your end users to modify them. Therefore, you can use the PromptOnCreate setting in the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] code to specify. If this value is set to true, then the fileIO library will prompt you whenever it attempts to Autocreate a data file. If it is set to false, then the fileIO library will create the data files without prompting you, like it always did before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;fnSettings:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The newest version of the FileIO library supports some features that require you to specify Global Settings values. These are done by modifying the contents of the [[#fnSettings_.28Global_Settings_Code.29|fnSettings]] routine at the beginning of the fileIO library.&lt;br /&gt;
&lt;br /&gt;
=== Fall 2006 ===&lt;br /&gt;
Many improvements have been made in the FileIO library over the summer. This section is intended to acquaint you with the highlights of those changes. Most of these improvements were built from ideas generated during the discussion at the April conference.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Intermixed String and Numeric Specs:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The File Library has been expanded to allow the reading of data files that contain mixed string and numeric specs. This is to aid those of you who are planning on implementing the FileIO Library on existing data files which may not be organized with strings first and numbers second.&lt;br /&gt;
&lt;br /&gt;
The central idea of the FileIO Library is based upon the reading of your data files into a String and Numeric array. This will enable you to refer to the fields in your file by using a named subscript, saying F$(FM_NAME) to refer, for example, to the farm file’s name field. The advantage to this is that when you change the file layout, all your existing programs will not have to be modified, because they will only be looking at F$(FM_NAME). If the name field changes from the third string field to the fourth, the value of FM_NAME will also change, and you won’t have to worry about updating your data files.&lt;br /&gt;
&lt;br /&gt;
However, in order to support the reading of a data file with intermixed string and numeric specs, the generated form statement will actually calculate the position of any fields that are not in order, so that the file read statement will still return all string fields first (into your string array) and the numeric fields second (into your numeric array). You do not need to worry about this; the library does it for you. All you have to do is read your file and use the data values.&lt;br /&gt;
&lt;br /&gt;
The only thing that is required is making sure that all your string subscript names end with a “$”. This will tell the library that they are strings. Thank you, George, for this suggestion.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Versioning / Automatic Updates:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The file layouts have been expanded to contain a version number. This version number will be used to determine when a file needs to be updated. The version number is the third parameter in the file layout.&lt;br /&gt;
&lt;br /&gt;
Any time you wish to change your file layouts, simply increment this version number. Each time the library attempts to open a data file, the file’s version is checked and compared with the version in the file layout. If the file layout has been changed (if the version in the file layout is greater then the version in the file) then the file will be updated to the latest version. Depending on the file size this may take a couple of moments. A simple progress bar will be displayed on screen while this is happening. The progress bar will be displayed in its own window, so it should not affect anything your programs may have had on screen.&lt;br /&gt;
&lt;br /&gt;
The library uses the following procedure for updating a file. First, the file is copied to a backup file (prefixed by the letter ‘o’ for old). So color.dat would become ocolor.dat, and color.key would become ocolor.key. Then the new file is created and marked with the proper version number. (color.dat, color.key). The old file is opened in read-only mode, and the new file is opened for OutIn. The update routine actually reads through the old file layout, and one record at a time creates a new record, using the new file layout, with the same data, saving it to the new data file.&lt;br /&gt;
&lt;br /&gt;
When it is done upgrading, the progress bar window is closed, and the file is reopened in the fashion you described in your call to fnOpen, and flow returns to your program as though nothing unusual has happened.&lt;br /&gt;
&lt;br /&gt;
If an error occurs during processing, the routine will do what it can to roll your data files back to the previous version, but please make frequent backups of your data files anyway, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Error Checking – If there is a mistake in the file layout:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The routine attempts to discover the cause of the error in the case that one is encountered due to a missing file, a file sharing violation, or an invalid or corrupt file layout. If this should happen, the program is paused, and a text message is printed out explaining the most likely source for the error, including what part of the file layout, if any, may have caused the error.&lt;br /&gt;
&lt;br /&gt;
You may then examine the printed text, and the contents of the BR system variables ERR and LINE to determine the problem. If you type “GO”, the next line will be execute “system”, ending your program.&lt;br /&gt;
&lt;br /&gt;
If the file was in the middle of an upgrade when the error happened, it will be automatically rolled back to the previous version, so that when you fix the problem and try to run your program again, the file will again attempt to update from the beginning, and you won’t have to worry about corrupted data.&lt;br /&gt;
&lt;br /&gt;
However, please backup your data before upgrading your data files anyway, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Implementation of Keys / Creation of New Data Files:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
The library has been expanded to automatically create all new data files, and to automatically update any existing files. This means that in the file layout header, two new fields that were previously ignored are no longer ignored. The RECL value that you specify in your file layout will be used, along with the description/definition of your keys file. When you open a new file (or update an existing one), the library will calculate the proper kps and kln by evaluating the key description. This key description must match up with subscript values from the data elements in your file, and more then one may be specified, but they must be separated with slashes (/). If I wanted my Farm File to be keyed based on CODE and NAME, the proper key description would be:&lt;br /&gt;
&lt;br /&gt;
  farm.key, CODE/NAME&lt;br /&gt;
&lt;br /&gt;
The library will then look up the position and length on disk of the CODE and NAME fields and put them together to create the proper keys during an update or creation of a new file. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;DataCrawler:&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
Perhaps the most exciting new addition to the library is the addition of a programming tool I like to call a DataCrawler. If you run the FileIO Library directly as a program, instead of using it as a library, it will function as a DataCrawler. The DataCrawler requires a New Gui version of BR, as it requires a ListView to be able to properly and easily display the data in your files.&lt;br /&gt;
&lt;br /&gt;
If you run it in an older version of BR you will get a message, telling you to run it in a newer copy. If you run it in a New Gui version of BR with CONFIG GUI OFF, then GUI will be turned temporarily on for the use of the DataCrawler and then turned off again when you are finished. If you run it in a New Gui version of BR with GUI ON, it will just run normally.&lt;br /&gt;
&lt;br /&gt;
When you run the DataCrawler, first you will see a ListView displaying every file layout it can find in the filelay folder. If you select a file, the DataCrawler will open a large ListView with as many columns as there are fields in the file. The Column Headings will come from the element descriptions in your data files, and the column widths will come from the displayed width of the fields. There will be a row for every record in your data file, and you can resize the column widths, and scroll around the data file to view the raw data of your BR data files on disk.&lt;br /&gt;
&lt;br /&gt;
If you are dealing with a particularly enormous data file (50,000+ records) it can take a moment to populate the ListView with the data in your data file. You may hit ESC to stop loading if you like, and view only the already loaded records.&lt;br /&gt;
&lt;br /&gt;
If you would like to look up a particular record (based only upon the primary key for the data file), you may press F4. This will give you a window which asks you to input the key or partial key. When you press enter, the file will be reloaded, starting at the key you specified and continuing on to the end of the file, or until you press ESC. The records you are looking for should appear at the top of the ListView.&lt;br /&gt;
&lt;br /&gt;
To reset the ListView and look at the contents of the entire file again, simply press F4, and enter a blank (“”) key.&lt;br /&gt;
&lt;br /&gt;
Finally, as with any ListView, you may resort your data by clicking on any of the column headings. Then you can use the slider bar at the right to scroll down to the record you desire.&lt;br /&gt;
&lt;br /&gt;
This is a programming tool and is not designed to be used by an end user. This tool will open your file in read-only mode. It will not allow you to modify the data; I leave that as an exercise for the reader. However, it will update any datafiles you view to the latest version (if they need to be updated) when it opens them, just as any other program that uses the library will do.&lt;br /&gt;
&lt;br /&gt;
== Appendix (Examples)==&lt;br /&gt;
&lt;br /&gt;
=== Example.br ===&lt;br /&gt;
  00010    ! example.br - This program is an example of for the data reading simplification&lt;br /&gt;
  00020    ! Copyright April 2006 by Gabriel Bakker&lt;br /&gt;
  00030    ! Distributed open source as a Christmas gift to brag members&lt;br /&gt;
  00040    !&lt;br /&gt;
  00100    execute &amp;quot;config gui off&amp;quot;&lt;br /&gt;
  01020    DIM form$(1)*255&lt;br /&gt;
  01030    DIM color$(1)*255,color(1)&lt;br /&gt;
  01040    DIM colorcat$(1)*255,colorcat(1)&lt;br /&gt;
  02020    library &amp;quot;fileio&amp;quot;: fnopenfile, fnreaddescription$&lt;br /&gt;
  04000 !&lt;br /&gt;
  04010 Openfiles: ! Open your files here&lt;br /&gt;
  04020    let colorfile=fnopen(&amp;quot;color&amp;quot;,mat color$,mat color,mat form$)&lt;br /&gt;
  04030    let colorcatfile=fnopen(&amp;quot;colorcat&amp;quot;,mat colorcat$,mat colorcat,mat form$,1)&lt;br /&gt;
  06000    ! gosub WriteFiles ! If you want to test this line, make sure to drop flag from 4030&lt;br /&gt;
  07000 !&lt;br /&gt;
  07010 MainBit: ! This&#039;un here&#039;s tha Main Bit&lt;br /&gt;
  07030    RESTORE #ColorFile:&lt;br /&gt;
  07100    ReadNextcolor: ! Read next record&lt;br /&gt;
  07120       read #ColorFile, using form$(ColorFile) : mat Color$, mat Color eof EndReadColor&lt;br /&gt;
  07180       PRINT Color$(co_name)&amp;amp;&amp;quot; (&amp;quot;&amp;amp;Color$(co_html)&amp;amp;&amp;quot;) is a member of the &#039;&amp;quot;;&lt;br /&gt;
  07190       PRINT trim$(fnReadDescription$(ColorcatFile,cc_Name,Color$(co_category),mat Colorcat$,mat Colorcat,mat form$))&amp;amp;&amp;quot;&#039; category.&amp;quot;&lt;br /&gt;
  07290       goto ReadNextColor&lt;br /&gt;
  07300    EndReadcolor: ! Finished with Color File&lt;br /&gt;
  08000    STOP&lt;br /&gt;
  25000 !&lt;br /&gt;
  25010 WriteFiles: ! Uncalled routine to demonstrate writing files&lt;br /&gt;
  25105       let color$(co_code)=&amp;quot;GD&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Gold&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;FFD700&amp;quot;&lt;br /&gt;
  25110       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25115       let color$(co_code)=&amp;quot;LV&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Lavender&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;BL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;E6E6FA&amp;quot;&lt;br /&gt;
  25120       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25125       let color$(co_Code)=&amp;quot;OR&amp;quot; !:&lt;br /&gt;
              let color$(co_Name)=&amp;quot;Orange&amp;quot; !:&lt;br /&gt;
              let color$(co_Category)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let color$(co_html)=&amp;quot;FFA500&amp;quot;&lt;br /&gt;
  25130       write #colorfile, using form$(colorfile): mat color$, mat color&lt;br /&gt;
  25205       let colorcat$(cc_Code)=&amp;quot;YL&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_Name)=&amp;quot;Yellows&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_html)=&amp;quot;FFFF00&amp;quot;&lt;br /&gt;
  25210       write #colorcatfile, using form$(colorcatfile): mat colorcat$,mat colorcat&lt;br /&gt;
  25215       let colorcat$(cc_Code)=&amp;quot;BL&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_Name)=&amp;quot;Blues&amp;quot; !:&lt;br /&gt;
              let colorcat$(cc_html)=&amp;quot;0000FF&amp;quot;&lt;br /&gt;
  25220       write #colorcatfile, using form$(colorcatfile): mat colorcat$,mat colorcat&lt;br /&gt;
  25300    return&lt;br /&gt;
  40000 !&lt;br /&gt;
  40010 Open: ! ***** Function to call library openfile and proc subs&lt;br /&gt;
  40020    def fnOpen(FILENAME$, MAT F$, MAT F, MAT FORM$;INPUTONLY,KEYNUM,___,INDEX)&lt;br /&gt;
  40025       dim _FileIOSubs$(1)*50&lt;br /&gt;
  40030       let fnopen=fnopenfile(FILENAME$, MAT F$, MAT F, MAT FORM$,INPUTONLY,KEYNUM,MAT _FileIOSubs$)&lt;br /&gt;
  40040       for Index=1 to udim(mat _FileIOSubs$) : execute (_FileIOSubs$(Index)) : next Index&lt;br /&gt;
  40090    fnend&lt;br /&gt;
  50000 !&lt;br /&gt;
  60000 Ignore: Continue&lt;br /&gt;
  &lt;br /&gt;
  Color File Layout&lt;br /&gt;
  color.dat, CO_, 1&lt;br /&gt;
  color.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Color Code,                  C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  CATEGORY$,      General Category of Color,   C    6&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
&lt;br /&gt;
  ColorCat File Layout&lt;br /&gt;
  colorcat.dat, CC_, 0&lt;br /&gt;
  colorcat.key, CODE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  CODE$,          Category Code,               C    6&lt;br /&gt;
  NAME$,          English Name for Color,      V   30&lt;br /&gt;
  HTML$,          HTML Code for the Color,     C    6&lt;br /&gt;
  &lt;br /&gt;
Example Layout showing multiple keys (price)&lt;br /&gt;
  price.dat, PR_, 0&lt;br /&gt;
  price.key, FARM&lt;br /&gt;
  price.ky2, ITEM&lt;br /&gt;
  price.ky3, FARM/ITEM/GRADE&lt;br /&gt;
  recl=127&lt;br /&gt;
  ===================================================&lt;br /&gt;
  FARM$,          Farm Code (or blank),        C    4&lt;br /&gt;
  ITEM$,          Item Code,                   C    4&lt;br /&gt;
  GRADE$,         Quality,                     C    4&lt;br /&gt;
  X,              Empty,                       X   37&lt;br /&gt;
  PRICE,          Default Price,               BH 3.2&lt;br /&gt;
  COST,           Default Cost,                BH 3.2&lt;br /&gt;
  XOPRICE,        Default Christmas Price,     BH 3.2&lt;br /&gt;
  XOCOST,         Default Christmas Cost,      BH 3.2&lt;br /&gt;
  MOPRICE,        Default Mothers D Price,     BH 3.2&lt;br /&gt;
  MOCOST,         Default Mothers D Cost,      BH 3.2&lt;br /&gt;
  VOPRICE,        Default Valentine Price,     BH 3.2&lt;br /&gt;
  VOCOST,         Default Valentine Cost,      BH 3.2&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10963</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10963"/>
		<updated>2018-09-18T16:01:11Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Completed Future Change Requests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from a julian date into the date format you specify, and when its writing it back to the disk, it will convert it back to the julian date value before saving it to the disk.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - this is obvious, but if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedKeys$&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to CurrentKey$ above. Therefore you can use Mat SelectedKeys$ to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedRecords&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to rec(Datafile) above. Therefore you can use Mat SelectedRecords to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10962</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10962"/>
		<updated>2018-09-18T15:44:48Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Completed Future Change Requests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables anyone to write complex user interfaces or complete custom programs, in a fraction of the time required by traditional development. We use it at [[Sage AX]] to write programs for our customers in record time, and we wanted to share it with you. For example, a fully functional File Maintenance program can now be created in half an hour. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using ScreenIO, the programs you create, called &amp;quot;screen functions&amp;quot;, integrate directly with your existing BR software and database and can be used to easily and impressively extend your existing software. Or you can use ScreenIO to design new software from the ground up, faster then you ever imagined possible.&lt;br /&gt;
&lt;br /&gt;
They&#039;re called &amp;quot;Screen Functions&amp;quot; because each one represents a piece of your User Interface, and they can be called from your existing software as Functions or run as standalone BR programs.&lt;br /&gt;
&lt;br /&gt;
You can run your Screen Functions in their own windows, or use them as part of an interface in your existing programs. Or you can place several screen functions together on tabs easily using the included run.br library. Some of our customers use Screen Functions to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
The benefit of using ScreenIO to extend your Business Rules software is that you can quickly modernize your interface in your important programs and very rapidly develop new programs, while leaving the backbone of your software, all the unseen processes and rarely used programs, working exactly the way they have been reliably working until now. This lets you focus your development on your most important projects and get results now.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from a julian date into the date format you specify, and when its writing it back to the disk, it will convert it back to the julian date value before saving it to the disk.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
Make these default functions by creating a regular event function in one of your screens, so that ScreenIO sets it up the right way. Then clear it out from that screen and move it into your &amp;quot;function\defaults&amp;quot; folder and rename it to the correct name for the event type that you want it to be. &lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported:&lt;br /&gt;
*enter.brs&lt;br /&gt;
*init.brs&lt;br /&gt;
*read.brs&lt;br /&gt;
*load.brs&lt;br /&gt;
*write.brs&lt;br /&gt;
*wait.brs&lt;br /&gt;
*locked.brs&lt;br /&gt;
*merge.brs*&lt;br /&gt;
*mainloop.brs&lt;br /&gt;
*nokey.brs*&lt;br /&gt;
*prelist.brs&lt;br /&gt;
*postlist.brs&lt;br /&gt;
*exit.brs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; * &amp;lt;/nowiki&amp;gt;Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run &#039;&#039;In addition to&#039;&#039; any function selected in the screen.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the [[CNVRT$]] function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - this is obvious, but if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedKeys$&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to CurrentKey$ above. Therefore you can use Mat SelectedKeys$ to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedRecords&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to rec(Datafile) above. Therefore you can use Mat SelectedRecords to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
*Support for Dates in any storage format on disk (ScreenIO 2.48)&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_14&amp;diff=10855</id>
		<title>Chapter 14</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_14&amp;diff=10855"/>
		<updated>2017-03-20T17:37:14Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* The SEQUENTIAL method of access with INTERNAL files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Now that you’ve had an introduction to the world of file processing, we’re going to dive right into the use of internal files.  When you finish this chapter you will be able to:&lt;br /&gt;
*Use and design a record layout.&lt;br /&gt;
*Create a new internal file using the OPEN statement.&lt;br /&gt;
*OPEN an existing internal file.&lt;br /&gt;
*Use the six I/O statements (READ, REREAD, WRITE, REWRITE, RESTORE and DELETE) for internal file processing in your programs.&lt;br /&gt;
&lt;br /&gt;
It is important for you to know about the overlap of this chapter with the next two chapters.  All three give you information about the important topic of processing internal files.  In many cases, the information that you learn later can also be applied to the information that you learned earlier -- so it is a very good idea to try to cover all three chapters in a short period of time, then come back and practice what you have learned.&lt;br /&gt;
&lt;br /&gt;
===14.1  Determining the record layout===&lt;br /&gt;
The very first step involved in creating an internal file is determining the layout of the records that the file is to hold.  This may seem like a fairly simple task, but it is also a very important task.  The programmer must make accurate judgments about the types and lengths of fields that a record is to hold, because inaccurate estimates can cause operational difficulties when the file is being used or extended.  Also, changing the record layout once a file has been filled with records can be a time-consuming and troublesome process.&lt;br /&gt;
&lt;br /&gt;
The following is an example of a record layout sheet for a file of information about checking account activity.  It lists all the fields in a single record and tells where each field is found within that record.  Throughout the remainder of the file processing section of this tutorial, this record layout will be used for a file called CHEKBOOK.INT.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|Field&lt;br /&gt;
|Description&lt;br /&gt;
|Form&lt;br /&gt;
|Positions&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|CHECK NUMBER&lt;br /&gt;
|N 5&lt;br /&gt;
|1-5&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|AMOUNT&lt;br /&gt;
|N 10.2&lt;br /&gt;
|6-15&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|DEPOSIT/WITHDRAWAL FLAG&lt;br /&gt;
|C 1&lt;br /&gt;
|16-16&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|DATE WRITTEN (YYMMDD)&lt;br /&gt;
|N 6&lt;br /&gt;
|17-22&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|DATE CLEARED (YYMMDD)&lt;br /&gt;
|N 6&lt;br /&gt;
|23-28&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|PAYEE&lt;br /&gt;
|C 25&lt;br /&gt;
|29-52&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|ACCOUNT NUMBER&lt;br /&gt;
|N 8&lt;br /&gt;
|54-62&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
According to the above layout, each record in CHECKBOOK.INT file is 62 characters long and contains a total of seven fields.&lt;br /&gt;
&lt;br /&gt;
===The SEQUENTIAL method of access with INTERNAL files===&lt;br /&gt;
Each of the seven fields (check number, amount, deposit/withdrawal flag, etc.) is described in the first column in the layout sheet.  The second column describes format of the fields; if you think back to the chapter that discussed formatted printing and use of the FORM statement, you should recognize the meanings of the figures in this column.  The third column lists the record positions that the fields will occupy.  Notice that there are no extra spaces between fields; since internal files cannot be seen by people anyway, there is no reason to make them readable by adding spaces between fields.&lt;br /&gt;
&lt;br /&gt;
To take the first field in the above layout as an example, the information that you should be able to determine from this entry is that check number is a numeric field which is 5 digits long and located in the first 5 bytes of the record.&lt;br /&gt;
&lt;br /&gt;
You might note that the third field is only one byte long.  Can anything important be stored in a one-byte field?  You betcha!  This little guy contains a D if the record is a deposit and a W if it is a withdrawal.  This one-byte indicator, sometimes called a flag, is stored in position 16.  In future references to the CHEKBOOK.INT file, we will assume that when there is a W in position 16 but no check number, the transaction that occurred involved a withdrawal that was not a check (perhaps it was a bank service charge or a cash machine withdrawal).&lt;br /&gt;
&lt;br /&gt;
You might also note that the descriptions of the fourth and fifth fields indicate that the date will be stored in the format YYMMDD (year first, then month, then day, with no slashes, hyphens or spaces as separators).  As the “Sorting Dates” box describes, this special date format makes the process of sorting information by date a quick and easy process.&lt;br /&gt;
&lt;br /&gt;
===Sorting Dates===&lt;br /&gt;
One of the ways that program users like to have information sorted is by date, and Business Rules! can do this quickly and easily when the date is stored as a six-digit number beginning with the year.&lt;br /&gt;
&lt;br /&gt;
When the date is stored as one six-digit number (rather than as three two-digit numbers), Business Rules! can handle the whole sorting process with just one sort specification rather than with three.  The trick to this one-specification process, however, is that the year has to occur first in the number.  If this doesn’t happen, the number representing some checks that were written at an earlier date will have a higher value than some written at a later date, and the sort won’t be accurate.&lt;br /&gt;
&lt;br /&gt;
As an example consider two checks, one written on 12-31-86, and the other written on 1-10-87.&lt;br /&gt;
&lt;br /&gt;
The first would be stored as 123186 when N 6 is the conversion specification, and the second would be stored as 011087.  If these two dates were sorted from lowest to highest, the sort would identify the 1986 check as having been written after the 1987 check.  Put the year first though, and 870110 will come out higher than 861231 every time.&lt;br /&gt;
&lt;br /&gt;
Most programmers don’t like the idea of asking operators to enter dates in the YYMMDD format.  The way to get around this is to have the operator enter in MMDDYY format and use a combination of substring and concatenation operations to change the order of the date before the number is stored.&lt;br /&gt;
&lt;br /&gt;
By the way, this is also the reason that the system variable DATE$ returns an 8-character string in YYMMDD format.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.1====&lt;br /&gt;
1) Number each of the following field descriptions according to their order in the CHEKBOOK.INT record layout: &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   The amount of the check.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   The person or company to whom the check was written.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   The withdrawal/deposit indicator.&amp;lt;br&amp;gt;&lt;br /&gt;
d)   The date the check was written.&amp;lt;br&amp;gt;&lt;br /&gt;
e)   The number of the check.&amp;lt;br&amp;gt;&lt;br /&gt;
f)   The date the check cleared the bank.&amp;lt;br&amp;gt;&lt;br /&gt;
g)   The account number of the person writing the check.&lt;br /&gt;
&lt;br /&gt;
2) Which of the following is often the best format for storing dates in an internal file?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   MM/DD/YY&amp;lt;br&amp;gt;&lt;br /&gt;
b)   MMDDYY&amp;lt;br&amp;gt;&lt;br /&gt;
c)   YYMMDD&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3.) What is the largest check amount that can be represented in the second field of the CHEKBOOK.INT file?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)  $9,999,999.99&amp;lt;br&amp;gt;&lt;br /&gt;
b)  $9,999,999,999.99&amp;lt;br&amp;gt;&lt;br /&gt;
c)  $99,999.99&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) If the CHEKBOOK.INT file contained 8000 records, approximately how much space would the entire file take up?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   8000 bytes.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   440,000 bytes.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Impossible to estimate.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NOTE: There are three correct answers for each of the remaining questions.&lt;br /&gt;
&lt;br /&gt;
5) The first field in the CHEKBOOK.INT file:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   Is an internal file.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   Is 6 bytes long.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Starts in position 1.&amp;lt;br&amp;gt;&lt;br /&gt;
d)   Ends in position 5.&amp;lt;br&amp;gt;&lt;br /&gt;
e)   Is a numeric field.&amp;lt;br&amp;gt;&lt;br /&gt;
f)   Is a string field.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6) The second field in the CHEKBOOK.INT file:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   Is an external file.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   Is 10 bytes long.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Starts in position 6.&amp;lt;br&amp;gt;&lt;br /&gt;
d)   Ends in position 16.&amp;lt;br&amp;gt;&lt;br /&gt;
e)   Includes a decimal point.&amp;lt;br&amp;gt;&lt;br /&gt;
f)   Is a string field.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7) The sixth field in the CHEKBOOK.INT file:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   Is an internal field.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   Is 25 bytes long.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Starts in position 6.&amp;lt;br&amp;gt;&lt;br /&gt;
d)   Ends in position 53.&amp;lt;br&amp;gt;&lt;br /&gt;
e)   Is a numeric field.&amp;lt;br&amp;gt;&lt;br /&gt;
f)   Is a string field.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.1]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.2  Suggestions for determining field lengths===&lt;br /&gt;
&lt;br /&gt;
When a single record is divided into fields, it is important to remember that the size of the field is predetermined and limited by the programmer.  Let’s take the information in the CHEKBOOK.INT file as an example.&lt;br /&gt;
&lt;br /&gt;
If the field for the payee’s name is 25 bytes long (meaning that it will allow for a total of no more than 25 letters, punctuation marks and spaces), then all payee names will have to fit in this space.  If a payee’s name is longer than this limit, the program operator will have to abbreviate it or else let the program truncate (chop the end off) it.  As you will learn later, the SOFLOW error condition can be used to catch this situation.  If the payee’s name is shorter than 25 keystrokes, spaces will fill the last few positions.&lt;br /&gt;
&lt;br /&gt;
Another field in CHEKBOOK.INT file is a 6-digit field (in YYMMDD format) for “date-cleared” the date the check clears the bank.  For a check that clears on October 22, 1987, this field could contain the 6-digit number 871022.  If someone tried to put an 8-digit number in this field, the program would probably generate an error.  (The CONV error condition can be used to trap this situation.)  If no error occurred, there would be trouble because the extra digits would spill over into some other field and invalidate (or “clobber”) its data.&lt;br /&gt;
&lt;br /&gt;
By now you may be thinking that it’s a good idea to overestimate the lengths of fields and to always provide a few extra bytes.  Sometimes this is true; adding a few extra bytes can be a sensible and necessary planning tool for the future.  As an example, imagine that you are creating a file that keeps track of product inventory for an auto parts company.  If the company currently has parts with identifying numbers that are up to 9000 and you know they will be over 10000 within a year, you should build this fact into the record design by allowing for a 5-byte field. (Besides, identifying numbers probably won’t go past 99999 for at least another 10 years.)&lt;br /&gt;
&lt;br /&gt;
So, yes, it can be a good idea to “pad” your fields with extra bytes.  But you should also keep in mind that unnecessary extra bytes on several fields can add up to a lot of wasted space.  In a product inventory file of 10,000 records, two extra bytes on each of five fields would be 2 x 5 x 10,000 = 100,000 extra bytes!&lt;br /&gt;
&lt;br /&gt;
===Using the OPEN statement to create a new file.===&lt;br /&gt;
As you may remember from the last chapter, the OPEN statement must be used whenever you wish to access a data file.  The OPEN statement must also be used when you wish to create a data file.&lt;br /&gt;
&lt;br /&gt;
Besides the line number and the OPEN keyword, the syntax of the OPEN statement contains five major parts: the file number, the file identification string, the file type, and the type of use and the method of access.  Keep in mind that, while the name and type of a file must remain constant, the same internal file can be opened for all different types of uses and methods of access.  The following OPEN statement creates the file CHEKBOOK.INT:&lt;br /&gt;
&lt;br /&gt;
 500 open #5: Name=&amp;quot;Checkbook.int, recl=63,new&amp;quot;, internal, output, sequential  &lt;br /&gt;
&lt;br /&gt;
The parts are: line number, OPEN, file number, file ID string, file type, method of access.&lt;br /&gt;
&lt;br /&gt;
While the length of this statement may make it look a bit intimidating, it really can be broken into some very logical and easy to understand parts.  Each of the following sections describes one of these parts in detail.&lt;br /&gt;
&lt;br /&gt;
;File number:&lt;br /&gt;
The file number is an arbitrary number from 1 to 127; it serves as a shortcut, or “nickname” for the file you are creating. Later in the program, instead of having to refer to CHEKBOOK.INT, you can just refer to #5.&lt;br /&gt;
&lt;br /&gt;
;File identification string:&lt;br /&gt;
The Name=“CHEKBOOK.INT,RECL=63” portion of the sample OPEN statement is the file identification string. This particular string contains three parts because this OPEN statement is being used to create a file. (When an OPEN statements is used to access a file that has already been created, the RECL= portions must be omitted.) The entire file identification string must always be enclosed within quotation marks or can be a string expression; letters may be uppercase, lowercase, or a mix of both.&lt;br /&gt;
&lt;br /&gt;
The three portions of this file identification string are as follows:&lt;br /&gt;
&lt;br /&gt;
1. &#039;&#039;&#039;NAME=&#039;&#039;&#039; - The five characters NAME= must be specified in the file identification string. After the equal sign, any valid filename may appear. Drive letter and full pathname are optional. This part of the OPEN statement is the only place in the entire program that the true name of the file needs to be referred to. Until the file is closed, Business Rules! will allow you to use the file number (#5, in our example) to refer to the file whenever necessary.&lt;br /&gt;
&lt;br /&gt;
2. &#039;&#039;&#039;RECL=&#039;&#039;&#039; - This second portion of the file identification string specifies the record length of the file to be created. It must be included in the string when a file is being created only.&lt;br /&gt;
&lt;br /&gt;
Notice that our sample OPEN statement creates CHEKBOOOK.INT with an initial size of zero bytes. The reason for this is that Business Rules! will automatically increase the file size as space is needed (this is called dynamic extension). To do this, the formula (RECL+1) * (expected # of records) is used.&lt;br /&gt;
&lt;br /&gt;
3. &#039;&#039;&#039;NEW&#039;&#039;&#039; - NEW indicates that the file to be opened must also be newly created. In the place of NEW, there are two other options: NEW or REPLACE.The USE parameter indicates that an existing file by the specified name should be opened. If a file by the specified name does not exist, Business Rules will create a new file for it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REPLACE&#039;&#039;&#039; indicates that any existing file under the specified name should be freed and that a new file under that same name be created. There will be no warning that the file is being replaced when this parameter is used.&lt;br /&gt;
&lt;br /&gt;
;File type:&lt;br /&gt;
The “INTERNAL” portion of the sample OPEN statement indicates the file type. There are three possible keywords that can appear here: INTERNAL, DISPLAY or EXTERNAL.&lt;br /&gt;
&lt;br /&gt;
;Method of access:&lt;br /&gt;
The “OUTPUT” portion of the sample OPEN statement indicates the method of access for the file. Since it is desirable for the records in this file to be placed one after the other, it has been opened for sequential access. The other methods of access that could be specified for internal files are RELATIVE and KEYED.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.2====&lt;br /&gt;
True or False:&lt;br /&gt;
&lt;br /&gt;
1. The RECL= clauses are part of the file identification string.&lt;br /&gt;
&lt;br /&gt;
2. RECL=0 is a good choice for new files.&lt;br /&gt;
&lt;br /&gt;
Answer:&amp;lt;br&amp;gt;&lt;br /&gt;
1. True&amp;lt;br&amp;gt;&lt;br /&gt;
2. False&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.3 Building the CHEKBOOK.INT file===&lt;br /&gt;
Now that you’ve learned how to create the internal file, you can begin filling it with data. The Business Rules! statement that adds records to internal files is the WRITE statement. The first rule to keep in mind about the WRITE statement is that the file it is adding information to must have already been opened with the OPEN statement. The OPEN statement that we used as our syntax example in the last lesson will work perfectly for our purposes (it is reprinted below). Type this statement into Business Rules!:&lt;br /&gt;
&lt;br /&gt;
 500 OPEN #5: “NAME=CHEKBOOK.INT,RECL=63,NEW”,INTERNAL,OUTPUT,SEQUENTIAL&lt;br /&gt;
&lt;br /&gt;
Now type in the following two lines:&lt;br /&gt;
&lt;br /&gt;
 600 WRITE #5,USING 700: 1044,106.45,”W”,871104,871112,”SAXO MUSIC”,10225340&lt;br /&gt;
 700 FORM N 5,N 10.2,C 1,N 6,N 6,C 25,N 8&lt;br /&gt;
&lt;br /&gt;
Go ahead and RUN this program. It will take only a few seconds and nothing much will seem to happen, but by the time the READY prompt shows in the bottom of your screen again your program will have created the CHEKBOOK.INT file and placed one record in it.&lt;br /&gt;
&lt;br /&gt;
How did all this work, you ask? Well, you should already be familiar with the OPEN statement in line 500. It told Business Rules! to create the file. And the WRITE statement in line 600 worked in conjunction with the FORM statement in line 700 to send a record to the file.&lt;br /&gt;
&lt;br /&gt;
If you look more closely at the WRITE statement, you’ll see that there is a colon just after the USING clause. The list of information after the colon represents the record that was added to the CHEKBOOK.INT file; each of the items corresponds to the fields in the CHEKBOOK.INT record layout.&lt;br /&gt;
&lt;br /&gt;
The information before the colon indicates where the record should be written (to #5, the nickname that the OPEN statement had just assigned to CHECKBOOK.INT). The USING clause in this half of the statement tells Business Rules! where to find the FORM statement that describes the format of the information to be written. The FORM statement in line 700 works in the same manner that it did when you used it with formatted printing. Note that each of the format identifiers in this statement follows exactly what was planned in the record layout.&lt;br /&gt;
&lt;br /&gt;
As you learn about other data-transferring I/O statements, you’ll find that they also follow the same general syntax as the WRITE statement. In each case, the colon acts as a major separator within the statement: the information after the colon indicates what is to be transferred, and the information before the colon explains how it is to be transferred.&lt;br /&gt;
&lt;br /&gt;
===Using the REPLACE parameter in the OPEN statement===&lt;br /&gt;
&lt;br /&gt;
Now, without making any changes to the program RUN it again. You should get an error. Look the error number up and see if you can figure out what happened. &lt;br /&gt;
&lt;br /&gt;
Error 4150 (duplicate file name) will occur. The reason that you got this error is that your OPEN statement in line 500 told Business Rules! to create a file that already existed (because this same program had created it just a few minutes earlier). Since the Business Rules! system does not want you to accidentally lose the contents of the existing file, it sends you a warning message in the form of an error. This error can save you from lots of trouble at times, but there will be other times when you’ll want to get rid of an old file by replacing it with an entirely new file.&lt;br /&gt;
&lt;br /&gt;
Business Rules! lets you take the risk of replacing an old file into your own hands by allowing you to code the keyword REPLACE in the file identification string of the OPEN statement.&lt;br /&gt;
&lt;br /&gt;
Doing this tells the system to replace any file that exists with the same name as the one you are creating. LIST your program and change the OPEN statement in line 500 as follows to do this:&lt;br /&gt;
&lt;br /&gt;
 500 OPEN #5: “NAME=CHEKBOOK.INT,RECL=63,REPLACE”,INTERNAL,OUTPUT,SEQUENTIAL&lt;br /&gt;
&lt;br /&gt;
Now you can run your new program as many times as you like.&lt;br /&gt;
&lt;br /&gt;
===Adding more records to CHEKBOOK.INT===&lt;br /&gt;
You could continue to add records to the CHEKBOOK.INT file by entering more WRITE statements that contain the exact data that needs to be entered. Each one would use the FORM statement in line 700 for the formatting.&lt;br /&gt;
&lt;br /&gt;
But the difficulties of building a file in this manner are extensive. First, it requires a programmer instead of a data entry operator. Most data files require the ongoing addition of records, and this is usually handled by a data entry professional who is quick and accurate. Second, it is slow, and third, it wastes a lot of program space.&lt;br /&gt;
&lt;br /&gt;
A much better way of handling the output of information from a program to a data file is to make it easy for somebody else to enter the information. As an example, look at the following program. It provides the operator with a screen (using full screen processing) that asks for all the information needed for a record: check number, amount, type of transaction, date written, date cleared, and payee and account number. It assigns this list of information to a set of variables labeled, and then uses a WRITE statement to send the whole set of variables to the CHEKBOOK.INT file.&lt;br /&gt;
&lt;br /&gt;
[[image:14.1.jpg|650px]]&lt;br /&gt;
&lt;br /&gt;
You should use this program to enter information from your own checkbook into the CHEKBOOK.INT file. Its available with your supplemental programs.&lt;br /&gt;
&lt;br /&gt;
====Mid-Chapter Practice====&lt;br /&gt;
The program CHEKBOOK.BRS uses a list of variables for each piece of information input by the user. This works great for simple programs, but with larger and more complicated projects, a better way to handle input from the user is to assign it all to an array. &lt;br /&gt;
&lt;br /&gt;
List the program and find line 190:&lt;br /&gt;
&lt;br /&gt;
 00190 INPUT FIELDS MAT inpdef$: chnum, amount, typetran$, datew, datec,&lt;br /&gt;
payee$,accnum&lt;br /&gt;
&lt;br /&gt;
Notice that the variables include both numbers and strings. The simplest way to combine both kinds of variables is to write two arrays, ENTRIES and ENTRIES$ and assign the values according to their place in line in the form statement, using POS.&lt;br /&gt;
&lt;br /&gt;
Your challenge is to re-write the appropriate lines (don’t forget to DIM these new arrays as well) so that the input is stored in these arrays. &lt;br /&gt;
&lt;br /&gt;
NOTE: There is a tool that can help you do this faster. In chapter 15, we describe a program called FileIO which can write parts of this code for you, once your program has been edited to work with it. It’s available online along with instructions.&lt;br /&gt;
&lt;br /&gt;
[[Solutions#CHAPTER 14|Solution]]&lt;br /&gt;
&lt;br /&gt;
===Quick Quiz 14.3===&lt;br /&gt;
1. True or False: When you create a new file, coding the REPLACE parameter at the end of the file identification string will override an error message when the file already exists.&lt;br /&gt;
&lt;br /&gt;
2. The purpose of the WRITE statement is:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) To add new records to a file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) To change existing records in a file.&amp;lt;br&amp;gt;&lt;br /&gt;
c) To generate handwriting on the screen.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. When a WRITE statement does not contain enough information for all the fields in the record, the positions in the record which are not specified in the FORM statement:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Will be written as blanks to the record.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Will contain any characters which may have been left on the disk by a previous file in that location.&lt;br /&gt;
&lt;br /&gt;
4. With files opened for sequential processing, the WRITE statement can only add records after:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) The first record in the file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) The last record in the file.&amp;lt;br&amp;gt;&lt;br /&gt;
c) The last record read.&amp;lt;br&amp;gt;&lt;br /&gt;
d) The next record pointed to by the file pointer.&lt;br /&gt;
&lt;br /&gt;
5. Data-items can include:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Everything that var-names can include.&amp;lt;br&amp;gt;&lt;br /&gt;
b) String and numeric constants.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Arithmetic expressions like 5*2.&amp;lt;br&amp;gt;&lt;br /&gt;
d) String and numeric functions.&amp;lt;br&amp;gt;&lt;br /&gt;
e) All of the above.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.3]]:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.4 Using the OPEN statement for an existing file.===&lt;br /&gt;
At this point, CHEKBOOK.INT should be a data file. What can you do with a file such as this? Use it in program processing!&lt;br /&gt;
&lt;br /&gt;
Imagine that you are the official programmer for Jack’s Country Bank, and that Jack would like to find out just how much money the bank is sending out each day and to whom. He would like to be able to print out a report of the amounts and recipients for all checks written. Using a combination of PRINT and READ statements, you can write a program that does just this.&lt;br /&gt;
&lt;br /&gt;
The first major step for a program that accomplishes this task is to open the internal file CHEKBOOK.INT. The OPEN statement for an existing file is very similar to the OPEN statement for creating a file except that you cannot include the RECL= or REPLACE parameters in the file identification string. If you did include RECL=, Business Rules! would attempt to create a new file with the name you specified and, finding that a file by that name already exists, it would send you an error message. If you also included the REPLACE parameter, Business Rules! would assume that you intended to replace the old file with a new one; it would automatically replace the contents of the file you specified with an empty file and all your data for that file and hard work would be lost.&lt;br /&gt;
&lt;br /&gt;
Type the following OPEN statement for the existing CHEKBOOK.INT into the Business Rules! system:&lt;br /&gt;
&lt;br /&gt;
 120 OPEN #7: “NAME=CHEKBOOK.INT”,INTERNAL,INPUT,SEQUENTIAL&lt;br /&gt;
&lt;br /&gt;
You may remember that we used #5 as the file number when we first created the CHEKBOOK.INT file; this time it is #7. The file number that you use in an OPEN statement can be any random number from 1 to 127, or it could even be the name of a variable that has a value from 1 to 127. It does not matter which number you choose; the only rule to remember is that all future references to the file must use this same number until the file is closed with a CLOSE statement (or until the program ends).&lt;br /&gt;
&lt;br /&gt;
Notice that the above statement opens CHEKBOOK.INT for input. This is because the information in the file will be input into the program.&lt;br /&gt;
&lt;br /&gt;
Now type in the following DIM, READ and FORM statements:&lt;br /&gt;
&lt;br /&gt;
 125 DIM NAME$*25&lt;br /&gt;
 130 For x=1 to 100&lt;br /&gt;
 135 READ #7, USING 140: AMOUNT, NAME$&lt;br /&gt;
 140 FORM X 5,N 10.2,X 13,C 25&lt;br /&gt;
&lt;br /&gt;
The DIM statement in line 125 dimensions the variable NAME$ so that it will hold all 25 characters of the string that will be assigned to it (otherwise, the default limit if 18 characters would apply).&lt;br /&gt;
&lt;br /&gt;
Notice how much the syntax of the READ statement in line 130 resembles the syntax of the WRITE statement you used earlier. However, its function is quite different. READ tells the system to go to the identified file and look up the fields that are identified in the corresponding FORM statement. Once the values in the fields have been located, they are assigned to the variables that are listed at the end of the READ statement for as long as they are used in the program.&lt;br /&gt;
&lt;br /&gt;
The above FORM statement tells the system to skip the first five bytes in the record, but to read the numeric field value in the next ten bytes (refer back to your record layout to find out which field this is). The next 13 bytes are also skipped and then a 25-character string value is read. The READ statement in line 130 tells the system to assign the values to the variables AMOUNT and NAME$.&lt;br /&gt;
&lt;br /&gt;
A program that reads all the records in the file requires some type of looping mechanism, but let’s get ahead of ourselves for a moment and simply add the statements necessary for printing out the requested values from the first record:&lt;br /&gt;
&lt;br /&gt;
 150 PRINT #255,USING 160: NAME$,AMOUNT&lt;br /&gt;
 160 FORM C 25,X 2,PIC($ZZ,ZZZ,ZZZ.##)&lt;br /&gt;
&lt;br /&gt;
The above two statements will send the information that the system has just read (and assigned to the variables NAME$ and AMOUNT) to the printer.&lt;br /&gt;
&lt;br /&gt;
Notice that the printing order of the values is inverted: the READ statement read them in the opposite order. Accordingly, the FORM statement also specifies format specifications in an order that matches the way the values will be printed. A PIC format identifier is used to format the AMOUNT value with commas in the printed number (if it’s large enough) and no leading zeroes.&lt;br /&gt;
&lt;br /&gt;
There is one other thing about these statements that you should pay attention to. The PRINT statement in line 150 refers to #255 which, as you learned in the printing chapter, is the special number that indicates a printer. This “special number” is actually a file number just as the numbers from 1 to 127 are. Can you remember what the other special file number in Business Rules! is? (Hint: it’s the default file number that tells Business Rules! to send all information to the screen.)&lt;br /&gt;
&lt;br /&gt;
You should now be able to RUN this five-line program without problems. The system will read and print the specified values that are in the first record of the CHEKBOOK.INT file.&lt;br /&gt;
&lt;br /&gt;
The next lesson will show you how to finish this program so that it reads the specified fields from all the records in the file, prints one line for each record in the file, and then prints a total at the end of the report.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.4====&lt;br /&gt;
1. Which is NOT part of the purpose of the OPEN statement for an existing file?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) It checks that the file exists.&amp;lt;br&amp;gt;&lt;br /&gt;
b) It searches all directories to find the file, wherever it is.&amp;lt;br&amp;gt;&lt;br /&gt;
c) It assigns a file number.&amp;lt;br&amp;gt;&lt;br /&gt;
d) It specifies the type of use (INPUT, OUTPUT, or OUTIN).&amp;lt;br&amp;gt;&lt;br /&gt;
e) It specifies the file type (INTERNAL, EXTERNAL or DISPLAY).&amp;lt;br&amp;gt;&lt;br /&gt;
f) It specifies the method of access (SEQUENTIAL, RELATIVE or KEYED).&lt;br /&gt;
&lt;br /&gt;
2. Which one is NOT true about a file number for internal files?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) It is part of the file identification string.&amp;lt;br&amp;gt;&lt;br /&gt;
b) It can range from 1 to 127.&amp;lt;br&amp;gt;&lt;br /&gt;
c) It is used as a shortcut way to refer to a file.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.4]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.5 Using the READ statement to get information from a file===&lt;br /&gt;
The sequential method of access (which is what your program is using now) works well when every record in the file must be accessed to obtain the desired information. This method causes the file pointer to always start at the first record in the file and read every single record in the same order that they were entered.&lt;br /&gt;
&lt;br /&gt;
The sequential method of access does not work as well when you need information from only a few records that are scattered throughout the file or when you want information from only a certain section of the records. In these cases and others that you will learn about later, the relative and keyed methods of access work better. You will learn more about these methods of access in the two chapters that follow this one.&lt;br /&gt;
&lt;br /&gt;
Now, let’s finish the program we started in the last lesson. The version of the program on your screen should already include lines 120-160 as they are coded below, with one exception: the EOF error condition has been added to the end of line 130. Make this one change, and then type lines 170 to 230 into your program.&lt;br /&gt;
&lt;br /&gt;
 100 ! ******************* L I S T A L C *************************&lt;br /&gt;
 101 ! PURPOSE: Report program to list and total all checks&lt;br /&gt;
 102 ! CREATION DATE: 7/22/05 LAST REVISION: 8/25/05&lt;br /&gt;
 103 ! Business Rules!&lt;br /&gt;
 104 ! ***********************************************************&lt;br /&gt;
 105 PRINT NEWPAGE&lt;br /&gt;
 120 OPEN #7: “NAME=CHEKBOOK.INT”,INTERNAL,INPUT,SEQUENTIAL&lt;br /&gt;
 125 DIM NAME$*25&lt;br /&gt;
 130 DO WHILE 1&lt;br /&gt;
 135 READ #7, USING 140: AMOUNT, NAME$ EOF 200&lt;br /&gt;
 140 FORM X 5, N 10.2, X 13, C 25&lt;br /&gt;
 150 PRINT #255, USING 160: NAME$, AMOUNT&lt;br /&gt;
 160 FORM C 25,X 2,PIC($ZZ,ZZZ,ZZZ.##)&lt;br /&gt;
 170 TOTAL=TOTAL+AMOUNT&lt;br /&gt;
 180 NCHECKS=NCHECKS+1&lt;br /&gt;
 190 LOOP&lt;br /&gt;
 200 PRINT #255,USING 210: NCHECKS, TOTAL&lt;br /&gt;
 210 FORM N 5,”Checks for a Total of “,PIC($Z,ZZZ,ZZZ,ZZZ.##)&lt;br /&gt;
 220 CLOSE #7:&lt;br /&gt;
 230 STOP&lt;br /&gt;
&lt;br /&gt;
The addition of lines 170 and 180 allows your program to include the current record in a totaling calculation; this calculation will be discussed later in this lesson. Line 190 transfers control back to line 130, where the next record will be read. The cycle of read a record, print, and do calculations is the program loop.&lt;br /&gt;
&lt;br /&gt;
Is there a way out of the loop from lines 130 to 190?&lt;br /&gt;
&lt;br /&gt;
This is where the EOF error condition that you coded into line 130 comes into play. EOF refers to the end-of-file error condition. This error will occur when an attempt is made to read after the last record in the file has already been read. Since this program provides no way out of the loop until the last record in the file is read, the loop will end after the last record has been read.&lt;br /&gt;
&lt;br /&gt;
When the EOF error does occur, the Business Rules! system will trap it because the EOF error condition is coded at the end of line 135. It will send program execution to the line number routine which is located at the line mentioned immediately after the letters EOF (line 200). The program execution continues from line 200.&lt;br /&gt;
&lt;br /&gt;
Now that you see how the loop operates, let’s examine the calculations inside the loop. Line 170 uses an accumulator to add the AMOUNT value of each check to another variable called TOTAL. At the end of the program, the value of TOTAL is the grand total of the amount of all checks.&lt;br /&gt;
&lt;br /&gt;
Each time that line 180 is executed, the number 1 is added to the counter variable called NCHECKS. At the end of the program, the value of NCHECKS is the total number of checks in the file. At any time in the middle of the loop, the number contained in NCHECKS is a count of the number of checks processed so far.&lt;br /&gt;
&lt;br /&gt;
After the last record has been read, printed, and the calculations performed, line 200 (which doesn’t get executed until the loop causes an error by reaching the end of the file) prints the final results of the calculations just discussed. The PRINT statement in line 200 uses the FORM statement in line 210. Notice that the text inside quotation marks in line 210 helps describe the number printed at the bottom of the report. For example, the bottom line might turn out to be:&lt;br /&gt;
&lt;br /&gt;
 27 Checks for a Total of $234,567,890.12&lt;br /&gt;
&lt;br /&gt;
Line 220 is a CLOSE statement. Just as the OPEN statement indicates the program is about to start using a file, the CLOSE statement indicates that the program is done using the file. Since the Business Rules! system automatically closes all open files when a program ends, you are not required to close them yourself. The use of the CLOSE statement becomes important only when the same program must open a large number of files; some operating systems limit the number of files you may use at one time, and even if yours does not, you will find that opening and working with too many files at once can severely affect your computer’s performance.&lt;br /&gt;
&lt;br /&gt;
The syntax of the CLOSE statement allows you to close the file and, if you wish, DROP or FREE its contents at the same time. The general syntax of the CLOSE statement is as follows.&lt;br /&gt;
&lt;br /&gt;
(Either the DROP or FREE keywords can be used in place of the optional “file-action” portion):&lt;br /&gt;
&lt;br /&gt;
 line# CLOSE #filenum: file-action&lt;br /&gt;
&lt;br /&gt;
The STOP statement in line 230 performs its usual function of ending the program. In addition, if there were no CLOSE statement, the STOP statement would cause all open files to be closed. The STOP, END, and CHAIN statements can all end a program and close all active files.&lt;br /&gt;
&lt;br /&gt;
Once you have this entire program typed in, go ahead and RUN it.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.5====&lt;br /&gt;
&lt;br /&gt;
True or False:&lt;br /&gt;
&lt;br /&gt;
1. The READ statement refers to a file by the file number.&lt;br /&gt;
&lt;br /&gt;
2. The colon in the READ statement separates the part of the statement that tells “how” the information should be read from the part that tells “what” information should be read.&lt;br /&gt;
&lt;br /&gt;
3. In the USING clause of a READ statement, a line number or line label must be the location of a FORM statement.&lt;br /&gt;
&lt;br /&gt;
4. The list of items that can follow the colon in a READ statement are called var-names.&lt;br /&gt;
&lt;br /&gt;
5. Var-names can include both variables and constants.&lt;br /&gt;
&lt;br /&gt;
6. EOF at the end of a READ statement is a special var-name that does not have to be preceded by a comma.&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.5]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.6 Using the REREAD statement with the READ statement===&lt;br /&gt;
Let’s take a second to visit with our old friend Zippy the Cursor as he reads a record in an internal file. When Zippy encounters a READ statement, he quickly runs to the specified internal file and finds the File pointer, who is pointing directly at the record he should access. Zippy gets the entire record, and then dashes back to the program and refers to the READ’s corresponding FORM statement. The FORM statement tells him which fields within the record are needed; Zippy finds these fields and assigns their values to the variable names that are listed at the end of the READ.&lt;br /&gt;
&lt;br /&gt;
He then goes on to execute the next program line, but he won’t forget the contents of the record that he just read until he executes another I/O statement for that file.&lt;br /&gt;
&lt;br /&gt;
In technical terms, the record that Zippy just read is held in an internal memory buffer (buffer is a fancy term for a temporary storage unit). It stays there until the next I/O statement is executed for that file.&lt;br /&gt;
&lt;br /&gt;
The reason for all this explanation is that we are going to tell you about the REREAD statement; its purpose is to read the record that was just read, again. REREAD can do this very efficiently because the record is still in the system’s memory buffer.&lt;br /&gt;
&lt;br /&gt;
Why would someone ever want to use the REREAD statement? Why not just use READ statements to read all the variables you want? The answer is that the REREAD statement can speed up your programs. This speed increase applies especially in programs that:&lt;br /&gt;
#must treat different kinds of records differently, and&lt;br /&gt;
#have lots of numeric fields (because it takes Business Rules! longer to translate numbers from a file to a program than it does to assign strings).&lt;br /&gt;
&lt;br /&gt;
As an example, let’s look at a program which can list and total all deposits (or all withdrawals) from the CHEKBOOK.INT file. This program asks whether the operator wants to list deposits or withdrawals. Suppose the operator asks for deposits (remember that the main way to tell the difference between deposits and withdrawals in the CHEKBOOK.INT file is that deposits have a “D” in position 16, but withdrawals have a “W”).&lt;br /&gt;
&lt;br /&gt;
The program has a loop that reads, prints, and totals. Before reading all the desired fields from every record, it first reads the one field needed to decide whether this record should be included or not. If position 16 does not contain a “D”, then the program goes back and reads the next record. The other fields are read by the REREAD statement, but only if the record has been selected based on information from the READ statement. Execution time is saved whenever the program can avoid reading fields form records that do not need to be included in the report.&lt;br /&gt;
&lt;br /&gt;
Before studying this program in detail, let’s take a look at the syntax of the REREAD statement:&lt;br /&gt;
&lt;br /&gt;
 line# REREAD #filenum USING line-ref: varname-list&lt;br /&gt;
&lt;br /&gt;
As is true for all other I/O statements, the use of REREAD requires that the file must first be opened. An additional rule for REREAD is that it can only be executed when it follows a successful READ or another REREAD statement (yes, there are times when you’ll want to use two or more REREAD statements in a row).&lt;br /&gt;
&lt;br /&gt;
 00100 ! ******************* L I S T D O R W *********************&lt;br /&gt;
 00200 ! PURPOSE: List all Deposits OR Withdrawals in CHEKBOOK.INT&lt;br /&gt;
 00300 ! CREATION DATE: 03/22/06 LAST REVISION : 04/12/06&lt;br /&gt;
 00400 ! Business Rules!&lt;br /&gt;
 00500 ! *********************************************************&lt;br /&gt;
 00600 PRINT NEWPAGE&lt;br /&gt;
 00700 LP=0 ! Change to 255 for output to printer&lt;br /&gt;
 00800 PRINT FIELDS “10,21,C 32”: “Enter D to list all DEPOSITS, or”&lt;br /&gt;
 00900 PRINT FIELDS “12,21,C 32”: “W to list all WITHDRAWALS”&lt;br /&gt;
 01000 PRINT FIELDS “14,21,C 32”: “E to end program”&lt;br /&gt;
 01100 PRINT FIELDS “17,21,C 32,b”: “Enter Choice”&lt;br /&gt;
 01200 INPUT FIELDS “17,37,C 1,rae”: OPT$&lt;br /&gt;
 01300 LET OPT$=UPRC$(OPT$) ! force OPT$ to be uppercase&lt;br /&gt;
 01400 IF OPT$=”E” THEN PRINT “Program Complete” : PRINT : STOP !: ELSE IF   &lt;br /&gt;
 OPT$=”D” THEN LET TYPE$=”Deposits” !:&lt;br /&gt;
 ELSE IF OPT$=”W” THEN LET TYPE$=”Withdrawals” !:&lt;br /&gt;
 ELSE PRINT FIELDS “17,37,C 1”: “ “ : GOTO 1200&lt;br /&gt;
 01500 PRINT #LP,USING FORMHEADING: TYPE$&lt;br /&gt;
 01600 !&lt;br /&gt;
 01700 ! file processing starts here&lt;br /&gt;
 01800 OPEN #5: “NAME=CHEKBOOK.INT”,INTERNAL,INPUT,SEQUENTIAL&lt;br /&gt;
 01900 !&lt;br /&gt;
 02000 MAINLOOP: READ #5,USING FORM5: DW$ EOF DONE&lt;br /&gt;
 02100 IF DW$&amp;lt;&amp;gt;OPT$ THEN GOTO MAINLOOP&lt;br /&gt;
 02200 REREAD #5,USING FORM5B: AMOUNT,DWDATE&lt;br /&gt;
 02300 PRINT #LP,USING FORMITEM: DWDATE,AMOUNT&lt;br /&gt;
 02400 LET N=N+1&lt;br /&gt;
 02500 LET TOTAL=TOTAL+AMOUNT&lt;br /&gt;
 02600 GOTO MAINLOOP&lt;br /&gt;
 02700 !&lt;br /&gt;
 02800 ! end-of-file processing&lt;br /&gt;
 02900 DONE: CLOSE #5:&lt;br /&gt;
 03000 PRINT #LP,USING FORMTOTAL: N,TYPE$,TOTAL&lt;br /&gt;
 03100 STOP&lt;br /&gt;
 03200 !&lt;br /&gt;
 03300 ! form statements used above&lt;br /&gt;
 03400 FORM5: FORM POS 16,C 1&lt;br /&gt;
 03500 FORM5B: FORM X 5,N 10.2,X 1,N 6&lt;br /&gt;
 03600 FORMHEADING: FORM POS 20,”List of entire checkbook “,C 20,SKIP 2,POS 36,C 8,SKIP 3&lt;br /&gt;
 03700 FORMITEM: FORM POS 30,PIC(Z#/##/##),POS 50, PIC($Z,ZZZ,ZZZ.##)&lt;br /&gt;
 03800 FORMTOTAL: FORM POS 49,”--------------“,SKIP 1,POS 12,N 5,X 2,C 13,”for a total of”,X 4,PIC($Z,ZZZ,ZZZ.##)&lt;br /&gt;
&lt;br /&gt;
Lines 700 to 1200 ask whether the report should include deposits or withdrawals. There is also a third option, to end the program without doing either one. If anything other than one of these three is selected, the program ignores the input and goes back for another choice (see line 1400). The 3-choice screen looks like this:&lt;br /&gt;
&lt;br /&gt;
[[image:14.2.jpg|650px]]&lt;br /&gt;
&lt;br /&gt;
To make the program more “user-friendly”, Business Rules! allows the report choice to be made with just one keystroke. Single-key input is accomplished with the control attributes “ae” in the INPUT FIELDS statement in line 1200.&lt;br /&gt;
&lt;br /&gt;
A second aspect of “user-friendly” input is that both uppercase and lowercase letters are allowed, using the UPRC$ function to convert any lowercase letters to uppercase before the three tests in line 1400. (The opposite of the UPRC$ function is LWRC$.)&lt;br /&gt;
&lt;br /&gt;
Line 1400 uses a single IF-THEN-ELSE statement to process four possible choices. The four possible cases for operator response are: “E”, “D”, “W” and everything else. Schematically, the structure of this statement could be described as IF-THEN-ELSEIF-ELSEIF-ELSE.&lt;br /&gt;
&lt;br /&gt;
Line 1400 tests first for the “E” or end option. If “E” is selected, the program prints the message “Program Complete” on the screen, then a blank line, and then stops. If either of the tests for “D” or “W” are true, the program sets the variable TYPE$ to “Deposits” or “Withdrawals”, respectively. If none of the first three tests are true, the final ELSE clause erases the operator’s response and branches to line 1200 to wait for another response. Only for a response of “D” or “W” will the program continue with line 1500 where a heading is printed for the report.&lt;br /&gt;
&lt;br /&gt;
If either of the tests for “D” or “W” are true, the program continues processing. Line 1800 opens the file, and lines 2000 to 2600 form the major loop of the program. Line 2000 reads the “D” or “W” in the third field of each record and assigns it to a variable called DW$. The FORM statement with the line label FORM5 (located in line 3400) tells the READ statement that the value for DW$ must come from the single character in position 16.&lt;br /&gt;
&lt;br /&gt;
Line 2100 compares the value of DW$ to the value of OPT$, which represents the operator’s choice about which type of records should be included in the report. If the two values are not equal, the record will be skipped. The GOTO MAINLOOP at the end of line 2100 ends processing for mismatching records because it sends the program back to the READ statement to begin processing the next record.&lt;br /&gt;
&lt;br /&gt;
How does the program get out of this loop from 2000 to 2600? The EOF condition on the end of line 2000 will eventually send control to the line label DONE at line 2900. Should the REREAD statement have an EOF clause too? No. It’s impossible for REREAD to encounter an end-of-file condition because it must always follow a successful READ or REREAD--and the READ statement will not be successful unless there is a record to read.&lt;br /&gt;
&lt;br /&gt;
The REREAD statement is especially useful in cases like the LISTDORW program where only certain records are being selected. Another situation where REREAD statements come in handy is when different types of records should be read in different ways. As an example, consider a program that is designed to print date and check number for all withdrawals. In both cases, the system could be designed to determine the type of transaction (“D” or “W”) with the READ statement; program execution could then be branched to the appropriate REREAD statement, each of which would require its own FORM statement.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.6====&lt;br /&gt;
True or False:&amp;lt;br&amp;gt;&lt;br /&gt;
1. The REREAD statement allows you to read a record that has just been read.&lt;br /&gt;
&lt;br /&gt;
2. You can speed up your programs by using the REREAD statement when selecting records instead of a READ statement for all fields in the record.&lt;br /&gt;
&lt;br /&gt;
3. The EOF error sometimes occurs on REREAD statements.&lt;br /&gt;
&lt;br /&gt;
4. Several REREAD statements could be executed consecutively without an error.&lt;br /&gt;
&lt;br /&gt;
5. After the Business Rules! system reads a record, the record stays in a memory buffer until when?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Until the next READ statement is executed.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Until the record is deleted.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Until the next I/O statement is executed.&lt;br /&gt;
&lt;br /&gt;
6. Which Business Rules! function changes all string input to uppercase letters?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) UPRC$&amp;lt;br&amp;gt;&lt;br /&gt;
b) UPCASE$&amp;lt;br&amp;gt;&lt;br /&gt;
c) UPRCL$&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.6]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.7 Deleting records===&lt;br /&gt;
The DELETE statement is used to remove a record from an internal file. The file must already be opened for OUTIN. The syntax is as follows:&lt;br /&gt;
&lt;br /&gt;
 DELETE #file-num, REC=numeric expression, RESERVE: error-condition line ref&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 DELETE #file-num, KEY=string expression, RELEASE: error-condition line ref&lt;br /&gt;
&lt;br /&gt;
The file number of the file from which the record is to be deleted must be identified with the &amp;quot;#file-num&amp;quot; parameter.&lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;REC=num-expr&amp;quot; clause is used with internal files opened for relative or keyed processing, or with external files opened for relative processing. After the numeric expression (usually a simple numeric variable or constant) is evaluated to an integer, the system performs an implied read and the record with that record number is deleted.  The REC= parameter may be used with files opened for either relative or keyed processing; using REC= in this manner will not disturb the key position in the file.  &lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;KEY=string-expr&amp;quot; clause is used with files opened for keyed processing; after the string expression is evaluated (usually a simple string variable or constant), the system performs an implied read and that record is deleted. &lt;br /&gt;
&lt;br /&gt;
If neither “REC=num-expr” (for files opened for RELATIVE access) nor “KEY=string-expr” (for KEYED access) is specified, the record deleted will always be the last one read.  Note: you cannot specify a KEY for RELATIVE-access files.  For SEQUENTIAL processing, the record deleted is always the last record that was read. After DELETE, the next record read will be the next active record after the deleted record. On the other hand, when deleting the record that was just read, you should not use the REC= or KEY= clauses, since they will just generate an unnecessary READ that slows down programs, especially with KEYED processing.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; DELETE must delete exactly one record when it is used. Therefore, in the KEY=n$ clause, the only form allowed is KEY=n$. KEY&amp;gt;=n$, SEARCH=n$, and SEARCH&amp;gt;=n$ are not allowed, as each of these can return 0 records or more than one record, whereas DELETE must delete exactly one record when it is used. (SEARCH and &amp;gt; are used to list files containing specified parts)&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;RESERVE&amp;quot; and &amp;quot;RELEASE&amp;quot; parameters specify record locking rules for multi-user systems. The default is that records are locked when they are read, and released when they are written. (So that if one person is accessing and editing a file, another person can’t READ and change it at the same time). RESERVE and RELEASE can change this default when desired by the programmer. &amp;quot;RESERVE&amp;quot; instructs the system to hold all previous locks and lock the current record. Locked records cannot be read.  &amp;quot;RELEASE&amp;quot; releases all locks and unlocks the current record. &lt;br /&gt;
&lt;br /&gt;
When DELETE is used, the record disappears but its space is not reclaimed automatically. If you want to reclaim that space, the easiest way to do this is using the COPY command with the -D option. (Basically copying the whole file but omitting deleted records). But when doing this, you must rebuild all indexes for that file because the COPY is likely to change relative record numbers, making the index file entries invalid. (Indexing is a way to organize your files).&lt;br /&gt;
&lt;br /&gt;
The positional parameters FIRST, LAST, PRIOR, NEXT, and SAME can be used with the DELETE statement to specify which record to delete from an opened file. These positional parameters can also be used with READ, RESTORE and REWRITE statements. For example:&lt;br /&gt;
&lt;br /&gt;
 DELETE NEXT&lt;br /&gt;
&lt;br /&gt;
The DELETE statement may be used to delete any anchor record or subrecord from a linked list. The DELETE statement must be preceded by a successful READ of the record to be deleted.&lt;br /&gt;
&lt;br /&gt;
Business Rules! will automatically update the next and previous record pointers (held in the first eight bytes of each linked record) of the affected records when a linked list record is deleted. If a linked list&#039;s anchor record is deleted, the next record in the list will become the anchor record. Also, the value of KREC will be updated to return the value of this new anchor record, no matter where the file pointer is in the list.&lt;br /&gt;
&lt;br /&gt;
===Using the REWRITE statement to change information in a file===&lt;br /&gt;
A slightly more complex task in sequential file processing is updating records, making changes to information that is already in a file.&lt;br /&gt;
&lt;br /&gt;
This job requires a combined effort from the READ statement (which finds the information to be changed) and the REWRITE statement (which performs the actual change).&lt;br /&gt;
&lt;br /&gt;
REWRITE is similar to REREAD in that it must follow a successful READ or REREAD statement before any other I/O statement is used. Unlike the REREAD statement, REWRITE statements cannot follow each other. A record can only be rewritten once for each time that it is read.&lt;br /&gt;
&lt;br /&gt;
To illustrate using the REWRITE statement, let’s look at an example of a program for Checkbook Reconciliation. When your bank statement comes, you need to compare your checkbook records to the bank’s records and resolve any differences--a process called reconciliation. At the beginning of the program the operator enters the date of the bank statement, which will later be output to the file for each record that has been cleared by the bank. This program reads each record (that is, looks at each check); it skips over checks and withdrawals that have already cleared (have a non-zero date cleared); then it rereads records that have not been cleared, and displays them on the screen.&lt;br /&gt;
&lt;br /&gt;
For each record displayed on the screen, the operator types Y or N for either “YES, this record has been cleared by the bank” or “NO, this record has not yet cleared the bank” (and needs to be considered outstanding until the next bank statement comes). When the operator says N, the program does not change this record, but goes on to get the next record. When the operator says Y, the program rewrites the record with a new date in the field for date cleared. Finally, the program goes on to read the next record. The program continues in this loop until the end of the file is reached, and then it displays the total number and total amount of deposits and withdrawals that have been cleared in this session.&lt;br /&gt;
&lt;br /&gt;
Here is the listing for the program, called RECONCYL:&lt;br /&gt;
&lt;br /&gt;
 00100 ! ********************** R E C O N C Y L *********************&lt;br /&gt;
 00200 ! PURPOSE: Reconcile bank statement and write date cleared.&lt;br /&gt;
 00300 ! CREATION DATE: 7/23/04 LAST REVISION: 8/21/04&lt;br /&gt;
 00400 ! Business Rules!.&lt;br /&gt;
 00500 ! ************************************************************&lt;br /&gt;
 00600 !&lt;br /&gt;
 00700 ! Get date of bank statement&lt;br /&gt;
 00800 PRINT NEWPAGE&lt;br /&gt;
 00900 PRINT FIELDS “10,26,C 30”: “Enter DATE from Bank Statement”&lt;br /&gt;
 01000 PRINT FIELDS “13,36,C 8”: DATE$(4:8)&amp;amp;”/”&amp;amp;DATE$(1:2) ! CHANGE TO MM/DD/YY&lt;br /&gt;
 01100 INPUT FIELD “13,36,pic(##/##/##),r”: BANKDATE&lt;br /&gt;
 01200 LET BANKDATE= FNYMD(BANKDATE)&lt;br /&gt;
 01300 !&lt;br /&gt;
 01400 ! Setup arrays for full screen processing&lt;br /&gt;
 01500 DIM PFDEFN$(8)*15,DFDEFN$(6)*25,PROMPT$(8)*16,PAYEE$*25&lt;br /&gt;
 01600 LET PFDEFN$(1)=”6,20,C 13”&lt;br /&gt;
 01700 LET PFDEFN$(2)=”8,20,C 13”&lt;br /&gt;
 01800 LET PFDEFN$(3)=”10,20,C 13”&lt;br /&gt;
 01900 LET PFDEFN$(4)=”12,20,C 13”&lt;br /&gt;
 02000 LET PFDEFN$(5)=”14,20,C 13”&lt;br /&gt;
 02100 LET PFDEFN$(6)=”15,20,C 13”&lt;br /&gt;
 02200 LET PFDEFN$(7)=”17,17,C 16,b”&lt;br /&gt;
 02300 LET PFDEFN$(8)=”18,30,C 3,b”&lt;br /&gt;
 02400 LET PROMPT$(1)=”Check Number:”&lt;br /&gt;
 02500 LET PROMPT$(2)=” Date:”&lt;br /&gt;
 02600 LET PROMPT$(3)=” Payee:”&lt;br /&gt;
 02700 LET PROMPT$(4)=” Amount:”&lt;br /&gt;
 02800 LET PROMPT$(5)=”D=Deposit or”&lt;br /&gt;
 02900 LET PROMPT$(6)=”Withdrawal”&lt;br /&gt;
 03000 LET PROMPT$(7)=”Clear this item?”&lt;br /&gt;
 03100 LET PROMPT$(8)=”Y/N”&lt;br /&gt;
 03200 LET DFDEFN$(1)=”6,36,N 5,u”&lt;br /&gt;
 03300 LET DFDEFN$(2)=”8,36,PIC(Z#/##/##),u”&lt;br /&gt;
 03400 LET DFDEFN$(3)=”10,36,C 25,u”&lt;br /&gt;
 03500 LET DFDEFN$(4)=”12,36,PIC(Z,ZZZ,ZZZ.##),u”&lt;br /&gt;
 03600 LET DFDEFN$(5)=”14,36,C 1,u”&lt;br /&gt;
 03700 LET DFDEFN$(6)=”18,36,C 1,r”&lt;br /&gt;
 03800 !&lt;br /&gt;
 03900 OPEN #5: “name=CHEKBOOK.INT”,INTERNAL,OUTIN,SEQUENTIAL&lt;br /&gt;
 04000 !&lt;br /&gt;
 04100 MAINLOOP: READ #5,USING FORM5: DATE_CLEARED EOF DONE&lt;br /&gt;
 04200 IF DATE_CLEARED&amp;lt;&amp;gt;0 THEN GOTO MAINLOOP&lt;br /&gt;
 04300 REREAD #5,USING FORM5B: CHECKNUM,AMOUNT,DW$,CHECKDATE,PAYEE$&lt;br /&gt;
 04400 PRINT NEWPAGE&lt;br /&gt;
 04500 PRINT FIELDS MAT PFDEFN$: MAT PROMPT$&lt;br /&gt;
 04600 PRINT FIELDS MAT DFDEFN$: CHECKNUM,CHECKDATE,PAYEE$,AMOUNT, DW$,”N”&lt;br /&gt;
 04700 INPUT FIELDS DFDEFN$(6): YESNO$&lt;br /&gt;
 04800 LET YESNO$=UPRC$(YESNO$)&lt;br /&gt;
 04900 IF YESNO$=”N” THEN GOTO MAINLOOP !:&lt;br /&gt;
 ELSE IF YESNO$&amp;lt;&amp;gt;”Y” THEN PRINT FIELDS DFDEFN$(6): “ “ : GOTO 4700&lt;br /&gt;
 05000 REWRITE #5,USING FORM5: BANKDATE&lt;br /&gt;
 05100 IF DW$=”D” THEN LET DTOTAL=DTOTAL+AMOUNT: LET NDEPS=NDEPS + 1 !:&lt;br /&gt;
 ELSE LET WTOTAL=WTOTAL+AMOUNT: LET NWDRAWS=NWDRAWS+1&lt;br /&gt;
 05200 GOTO MAINLOOP&lt;br /&gt;
 05300 !&lt;br /&gt;
 05400 ! End-of-file processing&lt;br /&gt;
 05500 DONE: CLOSE #5:&lt;br /&gt;
 05600 PRINT NEWPAGE;”Totals for Bank Statement”&lt;br /&gt;
 05700 PRINT&lt;br /&gt;
 05800 PRINT USING FORMTOTAL: NDEPS,”Deposits”,DTOTAL&lt;br /&gt;
 05900 PRINT USING FORMTOTAL: NWDRAWS,”Withdrawls”,WTOTAL&lt;br /&gt;
 06000 STOP&lt;br /&gt;
 06100 !&lt;br /&gt;
 06200 ! Function for date conversion MMDDYY to YYMMDD&lt;br /&gt;
 06300 DEF FNYMD(X)=(X-INT(X/10000)*10000)*100+INT(X/10000)&lt;br /&gt;
 06400 !&lt;br /&gt;
 06500 ! Form statements used above&lt;br /&gt;
 06600 FORM5: FORM POS 23,N 6&lt;br /&gt;
 06700 FORM5B: FORM N 5,N 10.2,C 1,N 6,X 6,C 25&lt;br /&gt;
 06800 FORMTOTAL: FORM N 5,X 1,C 11,” For a total of”,PIC($,$$Z,ZZZ.##),SKIP 2&lt;br /&gt;
&lt;br /&gt;
As the remarks indicate, lines 800 to 1400 ask the operator for the date of the bank statement. Lines 1700 to 3900 set up arrays to be used later for full-screen processing.&lt;br /&gt;
&lt;br /&gt;
In line 1000, the system variable DATE$, which contains the current system date, is used as an approximation to the date on the bank statement. Because the system date is a string in YYMMDD format, line 1000 uses substring and concatenation capabilities to change the date to MM/DD/YY format.&lt;br /&gt;
&lt;br /&gt;
Line 1200 calls a user-defined function FNYMD to convert the numeric date entered from YYMMDD format to MMDDYY format on the screen. User-defined functions can be placed anywhere in the program. FNYMD is located in line 6300.&lt;br /&gt;
&lt;br /&gt;
Line 3900 opens the file and assigns a file number of 5. To make changes to existing records in a sequential file, the file must be opened OUTIN. To remember this, it might help to think of updating as first inputting the old information, and then outputting the new information.&lt;br /&gt;
&lt;br /&gt;
The main processing loop starts in line 4100 and ends in line 5200. Lines 4100 to 4300 in this program are similar to lines 2000 to 2200 in the LISTDORW program that you studied earlier. Line 4100 reads the minimal information needed to find out if this record should be processed further. Line 4200 tests the information read by line 4100. In this case, the test is whether the field for date cleared has been set to a value other than zero.&lt;br /&gt;
&lt;br /&gt;
If this date is not zero, this record has already cleared the bank, so the program goes back to the start of the loop to read the next record.&lt;br /&gt;
&lt;br /&gt;
For records that have not already cleared the bank, the REREAD statement in line 4300 gets values for the other fields in this record so that the record can be displayed on the screen by the statements in lines 4400 to 4600. Here is the screen which asks the operator whether or not to clear this item.&lt;br /&gt;
&lt;br /&gt;
 Check Number: 12345&lt;br /&gt;
 &lt;br /&gt;
 Date: 10/22/12&lt;br /&gt;
 &lt;br /&gt;
 Payee: Corner Grocery Store&lt;br /&gt;
 &lt;br /&gt;
 Amount: 1,334.44&lt;br /&gt;
 &lt;br /&gt;
 D=Deposit or&lt;br /&gt;
 W=Withdrawal&lt;br /&gt;
 &lt;br /&gt;
 Clear this item?&lt;br /&gt;
 Y/N N&lt;br /&gt;
&lt;br /&gt;
 INPUT&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Again, like the LISTDORW program earlier in this chapter, the operator’s response is forced to be uppercase by line 4800. Line 4900 is an IF statement to consider three different possible operator responses: Y, N or something else. If the operator enters N, this item should not be cleared. If the first test in this IF statement indicates the operator entered N, the program does not rewrite anything, but just goes back to process the next record.&lt;br /&gt;
&lt;br /&gt;
The next case to be considered is when the operator’s reply is neither Y or N. Since the first part of the line has already called out all N responses, the second half of line 4900 needs only to determine that the response was not Y. If it does determine this, then the operator must have entered some other unexpected response. To give the operator another chance at answering the question properly, the input field is erased by writing a blank space on top of the old response, and then the program goes back to the INPUT FIELDS statement in line 4700.&lt;br /&gt;
&lt;br /&gt;
If the operator did enter Y, the program falls through all the parts of line 4900 to line 5000 where it rewrites the record so that the field for date cleared contains the date of the current bank statement. In line 5100, the program totals and counts the value of deposits and withdrawals separately. Line 5300 sends the program back to the start of the main loop to process the next record.&lt;br /&gt;
&lt;br /&gt;
FORM5 (found in line 6600) is the FORM statement used by the REWRITE statement in line 5000. Notice that FORM5 only refers to positions 23-28. It is important to know that the REWRITE statement does not change the other positions in the record. Only positions 23-28 are changed.&lt;br /&gt;
&lt;br /&gt;
When the end of the file is reached, the number of deposits and withdrawals are printed along with their total dollar values.&lt;br /&gt;
&lt;br /&gt;
Do you see any weaknesses in the way this program is designed? Think about what the program does when it reaches the end of the file. Try to come up with something yourself before reading the next paragraph.&lt;br /&gt;
&lt;br /&gt;
If the totals for the computer checkbook do not match the totals for the bank, what choices does the operator have? None! The CHEKBOOK.INT file is immediately changed each time the operator types Y, and there is no way in this program to undo what is done. So if the operator accidentally types Y instead of N even once, there is no way to correct the mistake. If the operator types N instead of Y, the program could be run again, but then the totals on the bank statement would not agree with the computer totals (but hopefully the two sets of computer totals could be added by hand to get the totals from the bank statement).&lt;br /&gt;
&lt;br /&gt;
Programs should not be designed so that the operator is required to never make even one mistake. Programs which do not allow any way to correct mistakes are called “unforgiving”. One characteristic of programs which are “user-friendly” is that they are forgiving.&lt;br /&gt;
&lt;br /&gt;
How could the above program be made forgiving? It would need to allow operators to change their minds about which checks have or have not cleared. This requires that the changes to individual records be temporary; there must be some way to get certain records--perhaps even the entire file--back to the way it was when the program started. There are several ways to do this. You could add another field to the record to indicate which fields are to be changed temporarily. Or you could change the rules for how the field for date cleared is processed, so that it can have temporary values (for example, only write the month and day, then add the year only after the totals have been accepted). The example program did not include any of these provisions, because it would make it harder for you to read and understand the main points; now that you see the big picture, it would be good for you to modify the program to be forgiving.&lt;br /&gt;
&lt;br /&gt;
Another way to make the program forgiving would be to copy the original file to a temporary file, and then make all the changes on the temporary file. If the totals at the end are not correct, then the program would erase the copy and keep the original file. If the totals are correct, the original file would be erased, and the temporary file would be renamed to become the corrected new CHEKBOOK.INT file. This method would be easy to code using Business Rules! commands and Business Rules!’s EXECUTE statement. Add these 7 statements. &lt;br /&gt;
&lt;br /&gt;
 03850 EXECUTE “COPY CHEKBOOK.INT CHEKBOOK.BAK”&lt;br /&gt;
 05910 PRINT “Are these totals correct?”&lt;br /&gt;
 05920 LINPUT YESNO$&lt;br /&gt;
 05930 YESNO$=LTRM$(YESNO$(1:1))&lt;br /&gt;
 05940 IF YESNO$=”Y” OR YESNO$=”y” THEN STOP&lt;br /&gt;
 05950 EXECUTE “FREE CHEKBOOK.INT”&lt;br /&gt;
 05960 EXECUTE “RENAME CHEKBOOK.BAK CHEKBOOK.INT”&lt;br /&gt;
 05970 PRINT “Original file restored. Run program again.” &lt;br /&gt;
&lt;br /&gt;
Line 4050 makes a backup copy of the file before it is opened in line 4100. Changes are made on the original file. After the totals are displayed in lines 5800 and 5900, the operator is asked if the totals are correct by the new lines 5910 and 5920. (If the operator’s response does not start with the letter Y.)&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.7====&lt;br /&gt;
1. The purpose of the REWRITE statement is:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) To add new records to a file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) To change existing records in a file.&amp;lt;br&amp;gt;&lt;br /&gt;
c) To prevent plagiarism.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. To use the REWRITE statement, a file must be opened with the keyword:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) INPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
b) OUTPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
c) OUTIN.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. When a REWRITE statement updates one field in the record, fields in the record which are not specified in the associated FORM statement:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Will be changed to blank spaces.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Will remain unchanged.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Will automatically be listed on the screen.&lt;br /&gt;
&lt;br /&gt;
4. With files opened for sequential processing, the REWRITE statement can only make changes to:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) The first record in the file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) The last record read.&amp;lt;br&amp;gt;&lt;br /&gt;
c) The last record deleted.&amp;lt;br&amp;gt;&lt;br /&gt;
d) The next record pointed to by the file pointer.&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.7]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.8 More about OUTPUT, INPUT and OUTIN===&lt;br /&gt;
You have now opened the CHEKBOOK.INT file in three different ways: for OUTPUT of information to a file; for INPUT of information from a file; and for both output to and input from the file (with OUTIN). Let’s consider each of these types of file use in more detail.&lt;br /&gt;
&lt;br /&gt;
;OUTPUT&lt;br /&gt;
Files should be opened for OUTPUT whenever you plan to only add new information to the file. OUTPUT implies that no information will be read from the file, and no existing information will be changed. Files opened for output may use the WRITE, DELETE and RESTORE I/O statements. The Business Rules! system does not allow the use of READ, REREAD or REWRITE statements on files which are open for output.&lt;br /&gt;
&lt;br /&gt;
;INPUT&lt;br /&gt;
Files should be opened for INPUT whenever the file will only be read, for example, in a program to print a report. INPUT implies that no new information will be added to the file, and none of the current information in the file will be changed. Files which are opened for input may use the READ, REREAD and RESTORE statements, but the Business Rules! system does not allow the use of DELETE, WRITE or REWRITE statements on files open for input.&lt;br /&gt;
&lt;br /&gt;
;OUTIN&lt;br /&gt;
OUTIN allows both input and output. It must be used when you wish to change information that already exists in the file. Files which are opened for outin may use all six of the I/O statements.&lt;br /&gt;
&lt;br /&gt;
After reading each of these descriptions, you may think that it’s a good idea to always code OUTIN if you are not sure how a file will be used. Especially for multi-user systems, however, this is not a good idea because it can increase system overhead. Also, other programmers expect a program to change a file when the OPEN statement specifies OUTIN. If your programs instead use OUTIN at random, they will be difficult and confusing for others to read. It is better to decide what is needed in the OPEN statement and code exactly what is needed. Also, this prevents accidentally writing or rewriting to a file by mistake (since a file opened for INPUT will throw an error if you attempt to write to it).&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.8====&lt;br /&gt;
1. A program that reads information in a file without changing it should specify which type of use in the OPEN statement?&amp;lt;br&amp;gt;&lt;br /&gt;
a) INPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
b) OUTPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
c) OUTIN.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2.  A program that changes information in a file should specify which type of use in the OPEN statement?&amp;lt;br&amp;gt;&lt;br /&gt;
a) INPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
b) OUTPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
c) OUTIN.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.8]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.9 The file pointer and the RESTORE statement===&lt;br /&gt;
Remember Zippy’s trusty friend the File Pointer? This diligent worker always keeps careful track of the next record to be accessed in an open data file. As a programmer, you must be aware of how the File Pointer operates so that you can predict which record will be accessed next.&lt;br /&gt;
&lt;br /&gt;
With sequential file processing, it is fairly simple to figure out which record will be accessed next because the file pointer always moves through the file sequentially, or one record at a time. With relative or keyed access, the file pointer starts where specified in the statement.&lt;br /&gt;
&lt;br /&gt;
Depending on how the file is opened, the file pointer starts out at either the beginning or end of a file that is to be sequentially processed. The file pointer always goes to the first record in the file when the OPEN statement specifies either INPUT,SEQUENTIAL or OUTIN,SEQUENTIAL. If you ever want to send the file pointer back to the beginning of the file to start accessing the same records all over again, you can use the RESTORE statement.&lt;br /&gt;
&lt;br /&gt;
RESTORE is one of the six I/O statements; when used with sequential processing, its syntax requires only the file number of the file to be restored. As an example of using RESTORE, imagine that you have opened CHEKBOOK.INT for sequential processing, but you are only interested in processing the first 20 withdrawal records. (Your program can use a counter variable to keep track of the number of times that the system completes the processing loop; when the value of the variable is 20, then you have processed the first 20 records.) Once this is done, you instruct the program to determine the average amount of each of the 20 checks. You then want it to go back to the beginning of the file and reprocess only those checks that were written for an amount that exceeds the average. The use of the RESTORE statement would cause the file pointer to move back to the beginning of the file even if it’s only half way through (rather than at the end) of the file at the time.&lt;br /&gt;
&lt;br /&gt;
An example of RESTORE when used in this situation could be:&lt;br /&gt;
&lt;br /&gt;
 7600 RESTORE #4:&lt;br /&gt;
&lt;br /&gt;
When OUTPUT,SEQUENTIAL is specified in the OPEN statement, the File Pointer knows that you probably want to add records to the end of the file--so he immediately positions himself after the last record. In case he was wrong about his prediction, the RESTORE statement can again be used to reposition the pointer at the beginning of the file. However, RESTORE used on a file opened OUTPUT,SEQUENTIAL will cause all existing records in the file to be erased. After a RESTORE on a file opened for output, the pointer is sitting at the beginning of an empty file. That’s good news if you wanted an empty file, but sometimes it can be bad news. Be careful with the RESTORE statement.&lt;br /&gt;
&lt;br /&gt;
The following two statements would open an imaginary data file called SALESCAL.INT for output of new records, and then empty the file of all existing records (same as a DROP command).&lt;br /&gt;
&lt;br /&gt;
 500 OPEN #5: “NAME=SALESCAL.INT”, INTERNAL,OUTPUT,SEQUENTIAL&lt;br /&gt;
 600 RESTORE #5:&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.9====&lt;br /&gt;
Fill in each of the banks below with either “beginning” or “end”:&lt;br /&gt;
&lt;br /&gt;
a) When a file is opened INPUT,SEQUENTIAL, the pointer is positioned at the _____________ of the file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) When a file is opened OUTPUT,SEQUENTIAL, the pointer is positioned at the _____________ of the file.&amp;lt;br&amp;gt;&lt;br /&gt;
c) When a file is opened OUTIN,SEQUENTIAL, the pointer is positioned at the _____________ of the file.&amp;lt;br&amp;gt;&lt;br /&gt;
d) The purpose of the RESTORE statement is to move the pointer to the _____________ of the file.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. To be able to read sequentially from an internal file, the best way to code the OPEN statement is:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) DISPLAY, OUTIN, SEQUENTIAL&amp;lt;br&amp;gt;&lt;br /&gt;
b) INTERNAL, OUTPUT, RELATIVE&amp;lt;br&amp;gt;&lt;br /&gt;
c) INTERNAL, INPUT, SEQUENTIAL&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. True or False: The best way to add records to the end of a long data file for OUTPUT,SEQUENTIAL, then use the RESTORE statement.&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.9]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NEXT:[[Chapter 15|The RELATIVE method of access for INTERNAL files]]&lt;br /&gt;
&lt;br /&gt;
[[BR Tutorial|Back to Index]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Tutorial 1]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_14&amp;diff=10854</id>
		<title>Chapter 14</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_14&amp;diff=10854"/>
		<updated>2017-03-17T18:59:39Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Using the REWRITE statement to change information in a file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Now that you’ve had an introduction to the world of file processing, we’re going to dive right into the use of internal files.  When you finish this chapter you will be able to:&lt;br /&gt;
*Use and design a record layout.&lt;br /&gt;
*Create a new internal file using the OPEN statement.&lt;br /&gt;
*OPEN an existing internal file.&lt;br /&gt;
*Use the six I/O statements (READ, REREAD, WRITE, REWRITE, RESTORE and DELETE) for internal file processing in your programs.&lt;br /&gt;
&lt;br /&gt;
It is important for you to know about the overlap of this chapter with the next two chapters.  All three give you information about the important topic of processing internal files.  In many cases, the information that you learn later can also be applied to the information that you learned earlier -- so it is a very good idea to try to cover all three chapters in a short period of time, then come back and practice what you have learned.&lt;br /&gt;
&lt;br /&gt;
===14.1  Determining the record layout===&lt;br /&gt;
The very first step involved in creating an internal file is determining the layout of the records that the file is to hold.  This may seem like a fairly simple task, but it is also a very important task.  The programmer must make accurate judgments about the types and lengths of fields that a record is to hold, because inaccurate estimates can cause operational difficulties when the file is being used or extended.  Also, changing the record layout once a file has been filled with records can be a time-consuming and troublesome process.&lt;br /&gt;
&lt;br /&gt;
The following is an example of a record layout sheet for a file of information about checking account activity.  It lists all the fields in a single record and tells where each field is found within that record.  Throughout the remainder of the file processing section of this tutorial, this record layout will be used for a file called CHEKBOOK.INT.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|Field&lt;br /&gt;
|Description&lt;br /&gt;
|Form&lt;br /&gt;
|Positions&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|CHECK NUMBER&lt;br /&gt;
|N 5&lt;br /&gt;
|1-5&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|AMOUNT&lt;br /&gt;
|N 10.2&lt;br /&gt;
|6-15&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|DEPOSIT/WITHDRAWAL FLAG&lt;br /&gt;
|C 1&lt;br /&gt;
|16-16&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|DATE WRITTEN (YYMMDD)&lt;br /&gt;
|N 6&lt;br /&gt;
|17-22&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|DATE CLEARED (YYMMDD)&lt;br /&gt;
|N 6&lt;br /&gt;
|23-28&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|PAYEE&lt;br /&gt;
|C 25&lt;br /&gt;
|29-52&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|ACCOUNT NUMBER&lt;br /&gt;
|N 8&lt;br /&gt;
|54-62&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
According to the above layout, each record in CHECKBOOK.INT file is 62 characters long and contains a total of seven fields.&lt;br /&gt;
&lt;br /&gt;
===The SEQUENTIAL method of access with INTERNAL files===&lt;br /&gt;
Each of the seven fields (check number, amount, deposit/withdrawal flag, etc.) is described in the first column in the layout sheet.  The second column describes format of the fields; if you think back to the chapter that discussed formatted printing and use of the FORM statement, you should recognize the meanings of the figures in this column.  The third column lists the record positions that the fields will occupy.  Notice that there are no extra spaces between fields; since internal files cannot be seen by people anyway, there is no reason to make them readable by adding spaces between fields.&lt;br /&gt;
&lt;br /&gt;
To take the first field in the above layout as an example, the information that you should be able to determine from this entry is that check number is a numeric field which is 5 digits long and located in the fist 5 bytes of the record.&lt;br /&gt;
&lt;br /&gt;
You might note that the third field is only one byte long.  Can anything important be stored in a one-byte field?  You betcha!  This little guy contains a D if the record is a deposit and a W if it is a withdrawal.  This one-byte indicator, sometimes called a flag, is stored in position 16.  In future references to the CHEKBOOK.INT file, we will assume that when there is a W in position 16 but no check number, the transaction that occurred involved a withdrawal that was not a check (perhaps it was a bank service charge or a cash machine withdrawal).&lt;br /&gt;
&lt;br /&gt;
You might also note that the descriptions of the fourth and fifth fields indicate that the date will be stored in the format YYMMDD (year first, then month, then day, with no slashes, hyphens or spaces as separators).  As the “Sorting Dates” box describes, this special date format makes the process of sorting information by date a quick and easy process.&lt;br /&gt;
&lt;br /&gt;
===Sorting Dates===&lt;br /&gt;
One of the ways that program users like to have information sorted is by date, and Business Rules! can do this quickly and easily when the date is stored as a six-digit number beginning with the year.&lt;br /&gt;
&lt;br /&gt;
When the date is stored as one six-digit number (rather than as three two-digit numbers), Business Rules! can handle the whole sorting process with just one sort specification rather than with three.  The trick to this one-specification process, however, is that the year has to occur first in the number.  If this doesn’t happen, the number representing some checks that were written at an earlier date will have a higher value than some written at a later date, and the sort won’t be accurate.&lt;br /&gt;
&lt;br /&gt;
As an example consider two checks, one written on 12-31-86, and the other written on 1-10-87.&lt;br /&gt;
&lt;br /&gt;
The first would be stored as 123186 when N 6 is the conversion specification, and the second would be stored as 011087.  If these two dates were sorted from lowest to highest, the sort would identify the 1986 check as having been written after the 1987 check.  Put the year first though, and 870110 will come out higher than 861231 every time.&lt;br /&gt;
&lt;br /&gt;
Most programmers don’t like the idea of asking operators to enter dates in the YYMMDD format.  The way to get around this is to have the operator enter in MMDDYY format and use a combination of substring and concatenation operations to change the order of the date before the number is stored.&lt;br /&gt;
&lt;br /&gt;
By the way, this is also the reason that the system variable DATE$ returns an 8-character string in YYMMDD format.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.1====&lt;br /&gt;
1) Number each of the following field descriptions according to their order in the CHEKBOOK.INT record layout: &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   The amount of the check.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   The person or company to whom the check was written.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   The withdrawal/deposit indicator.&amp;lt;br&amp;gt;&lt;br /&gt;
d)   The date the check was written.&amp;lt;br&amp;gt;&lt;br /&gt;
e)   The number of the check.&amp;lt;br&amp;gt;&lt;br /&gt;
f)   The date the check cleared the bank.&amp;lt;br&amp;gt;&lt;br /&gt;
g)   The account number of the person writing the check.&lt;br /&gt;
&lt;br /&gt;
2) Which of the following is often the best format for storing dates in an internal file?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   MM/DD/YY&amp;lt;br&amp;gt;&lt;br /&gt;
b)   MMDDYY&amp;lt;br&amp;gt;&lt;br /&gt;
c)   YYMMDD&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3.) What is the largest check amount that can be represented in the second field of the CHEKBOOK.INT file?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)  $9,999,999.99&amp;lt;br&amp;gt;&lt;br /&gt;
b)  $9,999,999,999.99&amp;lt;br&amp;gt;&lt;br /&gt;
c)  $99,999.99&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) If the CHEKBOOK.INT file contained 8000 records, approximately how much space would the entire file take up?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   8000 bytes.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   440,000 bytes.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Impossible to estimate.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NOTE: There are three correct answers for each of the remaining questions.&lt;br /&gt;
&lt;br /&gt;
5) The first field in the CHEKBOOK.INT file:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   Is an internal file.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   Is 6 bytes long.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Starts in position 1.&amp;lt;br&amp;gt;&lt;br /&gt;
d)   Ends in position 5.&amp;lt;br&amp;gt;&lt;br /&gt;
e)   Is a numeric field.&amp;lt;br&amp;gt;&lt;br /&gt;
f)   Is a string field.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6) The second field in the CHEKBOOK.INT file:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   Is an external file.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   Is 10 bytes long.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Starts in position 6.&amp;lt;br&amp;gt;&lt;br /&gt;
d)   Ends in position 16.&amp;lt;br&amp;gt;&lt;br /&gt;
e)   Includes a decimal point.&amp;lt;br&amp;gt;&lt;br /&gt;
f)   Is a string field.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7) The sixth field in the CHEKBOOK.INT file:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a)   Is an internal field.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   Is 25 bytes long.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Starts in position 6.&amp;lt;br&amp;gt;&lt;br /&gt;
d)   Ends in position 53.&amp;lt;br&amp;gt;&lt;br /&gt;
e)   Is a numeric field.&amp;lt;br&amp;gt;&lt;br /&gt;
f)   Is a string field.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.1]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.2  Suggestions for determining field lengths===&lt;br /&gt;
&lt;br /&gt;
When a single record is divided into fields, it is important to remember that the size of the field is predetermined and limited by the programmer.  Let’s take the information in the CHEKBOOK.INT file as an example.&lt;br /&gt;
&lt;br /&gt;
If the field for the payee’s name is 25 bytes long (meaning that it will allow for a total of no more than 25 letters, punctuation marks and spaces), then all payee names will have to fit in this space.  If a payee’s name is longer than this limit, the program operator will have to abbreviate it or else let the program truncate (chop the end off) it.  As you will learn later, the SOFLOW error condition can be used to catch this situation.  If the payee’s name is shorter than 25 keystrokes, spaces will fill the last few positions.&lt;br /&gt;
&lt;br /&gt;
Another field in CHEKBOOK.INT file is a 6-digit field (in YYMMDD format) for “date-cleared” the date the check clears the bank.  For a check that clears on October 22, 1987, this field could contain the 6-digit number 871022.  If someone tried to put an 8-digit number in this field, the program would probably generate an error.  (The CONV error condition can be used to trap this situation.)  If no error occurred, there would be trouble because the extra digits would spill over into some other field and invalidate (or “clobber”) its data.&lt;br /&gt;
&lt;br /&gt;
By now you may be thinking that it’s a good idea to overestimate the lengths of fields and to always provide a few extra bytes.  Sometimes this is true; adding a few extra bytes can be a sensible and necessary planning tool for the future.  As an example, imagine that you are creating a file that keeps track of product inventory for an auto parts company.  If the company currently has parts with identifying numbers that are up to 9000 and you know they will be over 10000 within a year, you should build this fact into the record design by allowing for a 5-byte field. (Besides, identifying numbers probably won’t go past 99999 for at least another 10 years.)&lt;br /&gt;
&lt;br /&gt;
So, yes, it can be a good idea to “pad” your fields with extra bytes.  But you should also keep in mind that unnecessary extra bytes on several fields can add up to a lot of wasted space.  In a product inventory file of 10,000 records, two extra bytes on each of five fields would be 2 x 5 x 10,000 = 100,000 extra bytes!&lt;br /&gt;
&lt;br /&gt;
===Using the OPEN statement to create a new file.===&lt;br /&gt;
As you may remember from the last chapter, the OPEN statement must be used whenever you wish to access a data file.  The OPEN statement must also be used when you wish to create a data file.&lt;br /&gt;
&lt;br /&gt;
Besides the line number and the OPEN keyword, the syntax of the OPEN statement contains five major parts: the file number, the file identification string, the file type, and the type of use and the method of access.  Keep in mind that, while the name and type of a file must remain constant, the same internal file can be opened for all different types of uses and methods of access.  The following OPEN statement creates the file CHEKBOOK.INT:&lt;br /&gt;
&lt;br /&gt;
 500 open #5: Name=&amp;quot;Checkbook.int, recl=63,new&amp;quot;, internal, output, sequential  &lt;br /&gt;
&lt;br /&gt;
The parts are: line number, OPEN, file number, file ID string, file type, method of access.&lt;br /&gt;
&lt;br /&gt;
While the length of this statement may make it look a bit intimidating, it really can be broken into some very logical and easy to understand parts.  Each of the following sections describes one of these parts in detail.&lt;br /&gt;
&lt;br /&gt;
;File number:&lt;br /&gt;
The file number is an arbitrary number from 1 to 127; it serves as a shortcut, or “nickname” for the file you are creating. Later in the program, instead of having to refer to CHEKBOOK.INT, you can just refer to #5.&lt;br /&gt;
&lt;br /&gt;
;File identification string:&lt;br /&gt;
The Name=“CHEKBOOK.INT,RECL=63” portion of the sample OPEN statement is the file identification string. This particular string contains three parts because this OPEN statement is being used to create a file. (When an OPEN statements is used to access a file that has already been created, the RECL= portions must be omitted.) The entire file identification string must always be enclosed within quotation marks or can be a string expression; letters may be uppercase, lowercase, or a mix of both.&lt;br /&gt;
&lt;br /&gt;
The three portions of this file identification string are as follows:&lt;br /&gt;
&lt;br /&gt;
1. &#039;&#039;&#039;NAME=&#039;&#039;&#039; - The five characters NAME= must be specified in the file identification string. After the equal sign, any valid filename may appear. Drive letter and full pathname are optional. This part of the OPEN statement is the only place in the entire program that the true name of the file needs to be referred to. Until the file is closed, Business Rules! will allow you to use the file number (#5, in our example) to refer to the file whenever necessary.&lt;br /&gt;
&lt;br /&gt;
2. &#039;&#039;&#039;RECL=&#039;&#039;&#039; - This second portion of the file identification string specifies the record length of the file to be created. It must be included in the string when a file is being created only.&lt;br /&gt;
&lt;br /&gt;
Notice that our sample OPEN statement creates CHEKBOOOK.INT with an initial size of zero bytes. The reason for this is that Business Rules! will automatically increase the file size as space is needed (this is called dynamic extension). To do this, the formula (RECL+1) * (expected # of records) is used.&lt;br /&gt;
&lt;br /&gt;
3. &#039;&#039;&#039;NEW&#039;&#039;&#039; - NEW indicates that the file to be opened must also be newly created. In the place of NEW, there are two other options: NEW or REPLACE.The USE parameter indicates that an existing file by the specified name should be opened. If a file by the specified name does not exist, Business Rules will create a new file for it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REPLACE&#039;&#039;&#039; indicates that any existing file under the specified name should be freed and that a new file under that same name be created. There will be no warning that the file is being replaced when this parameter is used.&lt;br /&gt;
&lt;br /&gt;
;File type:&lt;br /&gt;
The “INTERNAL” portion of the sample OPEN statement indicates the file type. There are three possible keywords that can appear here: INTERNAL, DISPLAY or EXTERNAL.&lt;br /&gt;
&lt;br /&gt;
;Method of access:&lt;br /&gt;
The “OUTPUT” portion of the sample OPEN statement indicates the method of access for the file. Since it is desirable for the records in this file to be placed one after the other, it has been opened for sequential access. The other methods of access that could be specified for internal files are RELATIVE and KEYED.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.2====&lt;br /&gt;
True or False:&lt;br /&gt;
&lt;br /&gt;
1. The RECL= clauses are part of the file identification string.&lt;br /&gt;
&lt;br /&gt;
2. RECL=0 is a good choice for new files.&lt;br /&gt;
&lt;br /&gt;
Answer:&amp;lt;br&amp;gt;&lt;br /&gt;
1. True&amp;lt;br&amp;gt;&lt;br /&gt;
2. False&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.3 Building the CHEKBOOK.INT file===&lt;br /&gt;
Now that you’ve learned how to create the internal file, you can begin filling it with data. The Business Rules! statement that adds records to internal files is the WRITE statement. The first rule to keep in mind about the WRITE statement is that the file it is adding information to must have already been opened with the OPEN statement. The OPEN statement that we used as our syntax example in the last lesson will work perfectly for our purposes (it is reprinted below). Type this statement into Business Rules!:&lt;br /&gt;
&lt;br /&gt;
 500 OPEN #5: “NAME=CHEKBOOK.INT,RECL=63,NEW”,INTERNAL,OUTPUT,SEQUENTIAL&lt;br /&gt;
&lt;br /&gt;
Now type in the following two lines:&lt;br /&gt;
&lt;br /&gt;
 600 WRITE #5,USING 700: 1044,106.45,”W”,871104,871112,”SAXO MUSIC”,10225340&lt;br /&gt;
 700 FORM N 5,N 10.2,C 1,N 6,N 6,C 25,N 8&lt;br /&gt;
&lt;br /&gt;
Go ahead and RUN this program. It will take only a few seconds and nothing much will seem to happen, but by the time the READY prompt shows in the bottom of your screen again your program will have created the CHEKBOOK.INT file and placed one record in it.&lt;br /&gt;
&lt;br /&gt;
How did all this work, you ask? Well, you should already be familiar with the OPEN statement in line 500. It told Business Rules! to create the file. And the WRITE statement in line 600 worked in conjunction with the FORM statement in line 700 to send a record to the file.&lt;br /&gt;
&lt;br /&gt;
If you look more closely at the WRITE statement, you’ll see that there is a colon just after the USING clause. The list of information after the colon represents the record that was added to the CHEKBOOK.INT file; each of the items corresponds to the fields in the CHEKBOOK.INT record layout.&lt;br /&gt;
&lt;br /&gt;
The information before the colon indicates where the record should be written (to #5, the nickname that the OPEN statement had just assigned to CHECKBOOK.INT). The USING clause in this half of the statement tells Business Rules! where to find the FORM statement that describes the format of the information to be written. The FORM statement in line 700 works in the same manner that it did when you used it with formatted printing. Note that each of the format identifiers in this statement follows exactly what was planned in the record layout.&lt;br /&gt;
&lt;br /&gt;
As you learn about other data-transferring I/O statements, you’ll find that they also follow the same general syntax as the WRITE statement. In each case, the colon acts as a major separator within the statement: the information after the colon indicates what is to be transferred, and the information before the colon explains how it is to be transferred.&lt;br /&gt;
&lt;br /&gt;
===Using the REPLACE parameter in the OPEN statement===&lt;br /&gt;
&lt;br /&gt;
Now, without making any changes to the program RUN it again. You should get an error. Look the error number up and see if you can figure out what happened. &lt;br /&gt;
&lt;br /&gt;
Error 4150 (duplicate file name) will occur. The reason that you got this error is that your OPEN statement in line 500 told Business Rules! to create a file that already existed (because this same program had created it just a few minutes earlier). Since the Business Rules! system does not want you to accidentally lose the contents of the existing file, it sends you a warning message in the form of an error. This error can save you from lots of trouble at times, but there will be other times when you’ll want to get rid of an old file by replacing it with an entirely new file.&lt;br /&gt;
&lt;br /&gt;
Business Rules! lets you take the risk of replacing an old file into your own hands by allowing you to code the keyword REPLACE in the file identification string of the OPEN statement.&lt;br /&gt;
&lt;br /&gt;
Doing this tells the system to replace any file that exists with the same name as the one you are creating. LIST your program and change the OPEN statement in line 500 as follows to do this:&lt;br /&gt;
&lt;br /&gt;
 500 OPEN #5: “NAME=CHEKBOOK.INT,RECL=63,REPLACE”,INTERNAL,OUTPUT,SEQUENTIAL&lt;br /&gt;
&lt;br /&gt;
Now you can run your new program as many times as you like.&lt;br /&gt;
&lt;br /&gt;
===Adding more records to CHEKBOOK.INT===&lt;br /&gt;
You could continue to add records to the CHEKBOOK.INT file by entering more WRITE statements that contain the exact data that needs to be entered. Each one would use the FORM statement in line 700 for the formatting.&lt;br /&gt;
&lt;br /&gt;
But the difficulties of building a file in this manner are extensive. First, it requires a programmer instead of a data entry operator. Most data files require the ongoing addition of records, and this is usually handled by a data entry professional who is quick and accurate. Second, it is slow, and third, it wastes a lot of program space.&lt;br /&gt;
&lt;br /&gt;
A much better way of handling the output of information from a program to a data file is to make it easy for somebody else to enter the information. As an example, look at the following program. It provides the operator with a screen (using full screen processing) that asks for all the information needed for a record: check number, amount, type of transaction, date written, date cleared, and payee and account number. It assigns this list of information to a set of variables labeled, and then uses a WRITE statement to send the whole set of variables to the CHEKBOOK.INT file.&lt;br /&gt;
&lt;br /&gt;
[[image:14.1.jpg|650px]]&lt;br /&gt;
&lt;br /&gt;
You should use this program to enter information from your own checkbook into the CHEKBOOK.INT file. Its available with your supplemental programs.&lt;br /&gt;
&lt;br /&gt;
====Mid-Chapter Practice====&lt;br /&gt;
The program CHEKBOOK.BRS uses a list of variables for each piece of information input by the user. This works great for simple programs, but with larger and more complicated projects, a better way to handle input from the user is to assign it all to an array. &lt;br /&gt;
&lt;br /&gt;
List the program and find line 190:&lt;br /&gt;
&lt;br /&gt;
 00190 INPUT FIELDS MAT inpdef$: chnum, amount, typetran$, datew, datec,&lt;br /&gt;
payee$,accnum&lt;br /&gt;
&lt;br /&gt;
Notice that the variables include both numbers and strings. The simplest way to combine both kinds of variables is to write two arrays, ENTRIES and ENTRIES$ and assign the values according to their place in line in the form statement, using POS.&lt;br /&gt;
&lt;br /&gt;
Your challenge is to re-write the appropriate lines (don’t forget to DIM these new arrays as well) so that the input is stored in these arrays. &lt;br /&gt;
&lt;br /&gt;
NOTE: There is a tool that can help you do this faster. In chapter 15, we describe a program called FileIO which can write parts of this code for you, once your program has been edited to work with it. It’s available online along with instructions.&lt;br /&gt;
&lt;br /&gt;
[[Solutions#CHAPTER 14|Solution]]&lt;br /&gt;
&lt;br /&gt;
===Quick Quiz 14.3===&lt;br /&gt;
1. True or False: When you create a new file, coding the REPLACE parameter at the end of the file identification string will override an error message when the file already exists.&lt;br /&gt;
&lt;br /&gt;
2. The purpose of the WRITE statement is:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) To add new records to a file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) To change existing records in a file.&amp;lt;br&amp;gt;&lt;br /&gt;
c) To generate handwriting on the screen.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. When a WRITE statement does not contain enough information for all the fields in the record, the positions in the record which are not specified in the FORM statement:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Will be written as blanks to the record.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Will contain any characters which may have been left on the disk by a previous file in that location.&lt;br /&gt;
&lt;br /&gt;
4. With files opened for sequential processing, the WRITE statement can only add records after:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) The first record in the file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) The last record in the file.&amp;lt;br&amp;gt;&lt;br /&gt;
c) The last record read.&amp;lt;br&amp;gt;&lt;br /&gt;
d) The next record pointed to by the file pointer.&lt;br /&gt;
&lt;br /&gt;
5. Data-items can include:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Everything that var-names can include.&amp;lt;br&amp;gt;&lt;br /&gt;
b) String and numeric constants.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Arithmetic expressions like 5*2.&amp;lt;br&amp;gt;&lt;br /&gt;
d) String and numeric functions.&amp;lt;br&amp;gt;&lt;br /&gt;
e) All of the above.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.3]]:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.4 Using the OPEN statement for an existing file.===&lt;br /&gt;
At this point, CHEKBOOK.INT should be a data file. What can you do with a file such as this? Use it in program processing!&lt;br /&gt;
&lt;br /&gt;
Imagine that you are the official programmer for Jack’s Country Bank, and that Jack would like to find out just how much money the bank is sending out each day and to whom. He would like to be able to print out a report of the amounts and recipients for all checks written. Using a combination of PRINT and READ statements, you can write a program that does just this.&lt;br /&gt;
&lt;br /&gt;
The first major step for a program that accomplishes this task is to open the internal file CHEKBOOK.INT. The OPEN statement for an existing file is very similar to the OPEN statement for creating a file except that you cannot include the RECL= or REPLACE parameters in the file identification string. If you did include RECL=, Business Rules! would attempt to create a new file with the name you specified and, finding that a file by that name already exists, it would send you an error message. If you also included the REPLACE parameter, Business Rules! would assume that you intended to replace the old file with a new one; it would automatically replace the contents of the file you specified with an empty file and all your data for that file and hard work would be lost.&lt;br /&gt;
&lt;br /&gt;
Type the following OPEN statement for the existing CHEKBOOK.INT into the Business Rules! system:&lt;br /&gt;
&lt;br /&gt;
 120 OPEN #7: “NAME=CHEKBOOK.INT”,INTERNAL,INPUT,SEQUENTIAL&lt;br /&gt;
&lt;br /&gt;
You may remember that we used #5 as the file number when we first created the CHEKBOOK.INT file; this time it is #7. The file number that you use in an OPEN statement can be any random number from 1 to 127, or it could even be the name of a variable that has a value from 1 to 127. It does not matter which number you choose; the only rule to remember is that all future references to the file must use this same number until the file is closed with a CLOSE statement (or until the program ends).&lt;br /&gt;
&lt;br /&gt;
Notice that the above statement opens CHEKBOOK.INT for input. This is because the information in the file will be input into the program.&lt;br /&gt;
&lt;br /&gt;
Now type in the following DIM, READ and FORM statements:&lt;br /&gt;
&lt;br /&gt;
 125 DIM NAME$*25&lt;br /&gt;
 130 For x=1 to 100&lt;br /&gt;
 135 READ #7, USING 140: AMOUNT, NAME$&lt;br /&gt;
 140 FORM X 5,N 10.2,X 13,C 25&lt;br /&gt;
&lt;br /&gt;
The DIM statement in line 125 dimensions the variable NAME$ so that it will hold all 25 characters of the string that will be assigned to it (otherwise, the default limit if 18 characters would apply).&lt;br /&gt;
&lt;br /&gt;
Notice how much the syntax of the READ statement in line 130 resembles the syntax of the WRITE statement you used earlier. However, its function is quite different. READ tells the system to go to the identified file and look up the fields that are identified in the corresponding FORM statement. Once the values in the fields have been located, they are assigned to the variables that are listed at the end of the READ statement for as long as they are used in the program.&lt;br /&gt;
&lt;br /&gt;
The above FORM statement tells the system to skip the first five bytes in the record, but to read the numeric field value in the next ten bytes (refer back to your record layout to find out which field this is). The next 13 bytes are also skipped and then a 25-character string value is read. The READ statement in line 130 tells the system to assign the values to the variables AMOUNT and NAME$.&lt;br /&gt;
&lt;br /&gt;
A program that reads all the records in the file requires some type of looping mechanism, but let’s get ahead of ourselves for a moment and simply add the statements necessary for printing out the requested values from the first record:&lt;br /&gt;
&lt;br /&gt;
 150 PRINT #255,USING 160: NAME$,AMOUNT&lt;br /&gt;
 160 FORM C 25,X 2,PIC($ZZ,ZZZ,ZZZ.##)&lt;br /&gt;
&lt;br /&gt;
The above two statements will send the information that the system has just read (and assigned to the variables NAME$ and AMOUNT) to the printer.&lt;br /&gt;
&lt;br /&gt;
Notice that the printing order of the values is inverted: the READ statement read them in the opposite order. Accordingly, the FORM statement also specifies format specifications in an order that matches the way the values will be printed. A PIC format identifier is used to format the AMOUNT value with commas in the printed number (if it’s large enough) and no leading zeroes.&lt;br /&gt;
&lt;br /&gt;
There is one other thing about these statements that you should pay attention to. The PRINT statement in line 150 refers to #255 which, as you learned in the printing chapter, is the special number that indicates a printer. This “special number” is actually a file number just as the numbers from 1 to 127 are. Can you remember what the other special file number in Business Rules! is? (Hint: it’s the default file number that tells Business Rules! to send all information to the screen.)&lt;br /&gt;
&lt;br /&gt;
You should now be able to RUN this five-line program without problems. The system will read and print the specified values that are in the first record of the CHEKBOOK.INT file.&lt;br /&gt;
&lt;br /&gt;
The next lesson will show you how to finish this program so that it reads the specified fields from all the records in the file, prints one line for each record in the file, and then prints a total at the end of the report.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.4====&lt;br /&gt;
1. Which is NOT part of the purpose of the OPEN statement for an existing file?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) It checks that the file exists.&amp;lt;br&amp;gt;&lt;br /&gt;
b) It searches all directories to find the file, wherever it is.&amp;lt;br&amp;gt;&lt;br /&gt;
c) It assigns a file number.&amp;lt;br&amp;gt;&lt;br /&gt;
d) It specifies the type of use (INPUT, OUTPUT, or OUTIN).&amp;lt;br&amp;gt;&lt;br /&gt;
e) It specifies the file type (INTERNAL, EXTERNAL or DISPLAY).&amp;lt;br&amp;gt;&lt;br /&gt;
f) It specifies the method of access (SEQUENTIAL, RELATIVE or KEYED).&lt;br /&gt;
&lt;br /&gt;
2. Which one is NOT true about a file number for internal files?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) It is part of the file identification string.&amp;lt;br&amp;gt;&lt;br /&gt;
b) It can range from 1 to 127.&amp;lt;br&amp;gt;&lt;br /&gt;
c) It is used as a shortcut way to refer to a file.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.4]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.5 Using the READ statement to get information from a file===&lt;br /&gt;
The sequential method of access (which is what your program is using now) works well when every record in the file must be accessed to obtain the desired information. This method causes the file pointer to always start at the first record in the file and read every single record in the same order that they were entered.&lt;br /&gt;
&lt;br /&gt;
The sequential method of access does not work as well when you need information from only a few records that are scattered throughout the file or when you want information from only a certain section of the records. In these cases and others that you will learn about later, the relative and keyed methods of access work better. You will learn more about these methods of access in the two chapters that follow this one.&lt;br /&gt;
&lt;br /&gt;
Now, let’s finish the program we started in the last lesson. The version of the program on your screen should already include lines 120-160 as they are coded below, with one exception: the EOF error condition has been added to the end of line 130. Make this one change, and then type lines 170 to 230 into your program.&lt;br /&gt;
&lt;br /&gt;
 100 ! ******************* L I S T A L C *************************&lt;br /&gt;
 101 ! PURPOSE: Report program to list and total all checks&lt;br /&gt;
 102 ! CREATION DATE: 7/22/05 LAST REVISION: 8/25/05&lt;br /&gt;
 103 ! Business Rules!&lt;br /&gt;
 104 ! ***********************************************************&lt;br /&gt;
 105 PRINT NEWPAGE&lt;br /&gt;
 120 OPEN #7: “NAME=CHEKBOOK.INT”,INTERNAL,INPUT,SEQUENTIAL&lt;br /&gt;
 125 DIM NAME$*25&lt;br /&gt;
 130 DO WHILE 1&lt;br /&gt;
 135 READ #7, USING 140: AMOUNT, NAME$ EOF 200&lt;br /&gt;
 140 FORM X 5, N 10.2, X 13, C 25&lt;br /&gt;
 150 PRINT #255, USING 160: NAME$, AMOUNT&lt;br /&gt;
 160 FORM C 25,X 2,PIC($ZZ,ZZZ,ZZZ.##)&lt;br /&gt;
 170 TOTAL=TOTAL+AMOUNT&lt;br /&gt;
 180 NCHECKS=NCHECKS+1&lt;br /&gt;
 190 LOOP&lt;br /&gt;
 200 PRINT #255,USING 210: NCHECKS, TOTAL&lt;br /&gt;
 210 FORM N 5,”Checks for a Total of “,PIC($Z,ZZZ,ZZZ,ZZZ.##)&lt;br /&gt;
 220 CLOSE #7:&lt;br /&gt;
 230 STOP&lt;br /&gt;
&lt;br /&gt;
The addition of lines 170 and 180 allows your program to include the current record in a totaling calculation; this calculation will be discussed later in this lesson. Line 190 transfers control back to line 130, where the next record will be read. The cycle of read a record, print, and do calculations is the program loop.&lt;br /&gt;
&lt;br /&gt;
Is there a way out of the loop from lines 130 to 190?&lt;br /&gt;
&lt;br /&gt;
This is where the EOF error condition that you coded into line 130 comes into play. EOF refers to the end-of-file error condition. This error will occur when an attempt is made to read after the last record in the file has already been read. Since this program provides no way out of the loop until the last record in the file is read, the loop will end after the last record has been read.&lt;br /&gt;
&lt;br /&gt;
When the EOF error does occur, the Business Rules! system will trap it because the EOF error condition is coded at the end of line 135. It will send program execution to the line number routine which is located at the line mentioned immediately after the letters EOF (line 200). The program execution continues from line 200.&lt;br /&gt;
&lt;br /&gt;
Now that you see how the loop operates, let’s examine the calculations inside the loop. Line 170 uses an accumulator to add the AMOUNT value of each check to another variable called TOTAL. At the end of the program, the value of TOTAL is the grand total of the amount of all checks.&lt;br /&gt;
&lt;br /&gt;
Each time that line 180 is executed, the number 1 is added to the counter variable called NCHECKS. At the end of the program, the value of NCHECKS is the total number of checks in the file. At any time in the middle of the loop, the number contained in NCHECKS is a count of the number of checks processed so far.&lt;br /&gt;
&lt;br /&gt;
After the last record has been read, printed, and the calculations performed, line 200 (which doesn’t get executed until the loop causes an error by reaching the end of the file) prints the final results of the calculations just discussed. The PRINT statement in line 200 uses the FORM statement in line 210. Notice that the text inside quotation marks in line 210 helps describe the number printed at the bottom of the report. For example, the bottom line might turn out to be:&lt;br /&gt;
&lt;br /&gt;
 27 Checks for a Total of $234,567,890.12&lt;br /&gt;
&lt;br /&gt;
Line 220 is a CLOSE statement. Just as the OPEN statement indicates the program is about to start using a file, the CLOSE statement indicates that the program is done using the file. Since the Business Rules! system automatically closes all open files when a program ends, you are not required to close them yourself. The use of the CLOSE statement becomes important only when the same program must open a large number of files; some operating systems limit the number of files you may use at one time, and even if yours does not, you will find that opening and working with too many files at once can severely affect your computer’s performance.&lt;br /&gt;
&lt;br /&gt;
The syntax of the CLOSE statement allows you to close the file and, if you wish, DROP or FREE its contents at the same time. The general syntax of the CLOSE statement is as follows.&lt;br /&gt;
&lt;br /&gt;
(Either the DROP or FREE keywords can be used in place of the optional “file-action” portion):&lt;br /&gt;
&lt;br /&gt;
 line# CLOSE #filenum: file-action&lt;br /&gt;
&lt;br /&gt;
The STOP statement in line 230 performs its usual function of ending the program. In addition, if there were no CLOSE statement, the STOP statement would cause all open files to be closed. The STOP, END, and CHAIN statements can all end a program and close all active files.&lt;br /&gt;
&lt;br /&gt;
Once you have this entire program typed in, go ahead and RUN it.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.5====&lt;br /&gt;
&lt;br /&gt;
True or False:&lt;br /&gt;
&lt;br /&gt;
1. The READ statement refers to a file by the file number.&lt;br /&gt;
&lt;br /&gt;
2. The colon in the READ statement separates the part of the statement that tells “how” the information should be read from the part that tells “what” information should be read.&lt;br /&gt;
&lt;br /&gt;
3. In the USING clause of a READ statement, a line number or line label must be the location of a FORM statement.&lt;br /&gt;
&lt;br /&gt;
4. The list of items that can follow the colon in a READ statement are called var-names.&lt;br /&gt;
&lt;br /&gt;
5. Var-names can include both variables and constants.&lt;br /&gt;
&lt;br /&gt;
6. EOF at the end of a READ statement is a special var-name that does not have to be preceded by a comma.&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.5]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.6 Using the REREAD statement with the READ statement===&lt;br /&gt;
Let’s take a second to visit with our old friend Zippy the Cursor as he reads a record in an internal file. When Zippy encounters a READ statement, he quickly runs to the specified internal file and finds the File pointer, who is pointing directly at the record he should access. Zippy gets the entire record, and then dashes back to the program and refers to the READ’s corresponding FORM statement. The FORM statement tells him which fields within the record are needed; Zippy finds these fields and assigns their values to the variable names that are listed at the end of the READ.&lt;br /&gt;
&lt;br /&gt;
He then goes on to execute the next program line, but he won’t forget the contents of the record that he just read until he executes another I/O statement for that file.&lt;br /&gt;
&lt;br /&gt;
In technical terms, the record that Zippy just read is held in an internal memory buffer (buffer is a fancy term for a temporary storage unit). It stays there until the next I/O statement is executed for that file.&lt;br /&gt;
&lt;br /&gt;
The reason for all this explanation is that we are going to tell you about the REREAD statement; its purpose is to read the record that was just read, again. REREAD can do this very efficiently because the record is still in the system’s memory buffer.&lt;br /&gt;
&lt;br /&gt;
Why would someone ever want to use the REREAD statement? Why not just use READ statements to read all the variables you want? The answer is that the REREAD statement can speed up your programs. This speed increase applies especially in programs that:&lt;br /&gt;
#must treat different kinds of records differently, and&lt;br /&gt;
#have lots of numeric fields (because it takes Business Rules! longer to translate numbers from a file to a program than it does to assign strings).&lt;br /&gt;
&lt;br /&gt;
As an example, let’s look at a program which can list and total all deposits (or all withdrawals) from the CHEKBOOK.INT file. This program asks whether the operator wants to list deposits or withdrawals. Suppose the operator asks for deposits (remember that the main way to tell the difference between deposits and withdrawals in the CHEKBOOK.INT file is that deposits have a “D” in position 16, but withdrawals have a “W”).&lt;br /&gt;
&lt;br /&gt;
The program has a loop that reads, prints, and totals. Before reading all the desired fields from every record, it first reads the one field needed to decide whether this record should be included or not. If position 16 does not contain a “D”, then the program goes back and reads the next record. The other fields are read by the REREAD statement, but only if the record has been selected based on information from the READ statement. Execution time is saved whenever the program can avoid reading fields form records that do not need to be included in the report.&lt;br /&gt;
&lt;br /&gt;
Before studying this program in detail, let’s take a look at the syntax of the REREAD statement:&lt;br /&gt;
&lt;br /&gt;
 line# REREAD #filenum USING line-ref: varname-list&lt;br /&gt;
&lt;br /&gt;
As is true for all other I/O statements, the use of REREAD requires that the file must first be opened. An additional rule for REREAD is that it can only be executed when it follows a successful READ or another REREAD statement (yes, there are times when you’ll want to use two or more REREAD statements in a row).&lt;br /&gt;
&lt;br /&gt;
 00100 ! ******************* L I S T D O R W *********************&lt;br /&gt;
 00200 ! PURPOSE: List all Deposits OR Withdrawals in CHEKBOOK.INT&lt;br /&gt;
 00300 ! CREATION DATE: 03/22/06 LAST REVISION : 04/12/06&lt;br /&gt;
 00400 ! Business Rules!&lt;br /&gt;
 00500 ! *********************************************************&lt;br /&gt;
 00600 PRINT NEWPAGE&lt;br /&gt;
 00700 LP=0 ! Change to 255 for output to printer&lt;br /&gt;
 00800 PRINT FIELDS “10,21,C 32”: “Enter D to list all DEPOSITS, or”&lt;br /&gt;
 00900 PRINT FIELDS “12,21,C 32”: “W to list all WITHDRAWALS”&lt;br /&gt;
 01000 PRINT FIELDS “14,21,C 32”: “E to end program”&lt;br /&gt;
 01100 PRINT FIELDS “17,21,C 32,b”: “Enter Choice”&lt;br /&gt;
 01200 INPUT FIELDS “17,37,C 1,rae”: OPT$&lt;br /&gt;
 01300 LET OPT$=UPRC$(OPT$) ! force OPT$ to be uppercase&lt;br /&gt;
 01400 IF OPT$=”E” THEN PRINT “Program Complete” : PRINT : STOP !: ELSE IF   &lt;br /&gt;
 OPT$=”D” THEN LET TYPE$=”Deposits” !:&lt;br /&gt;
 ELSE IF OPT$=”W” THEN LET TYPE$=”Withdrawals” !:&lt;br /&gt;
 ELSE PRINT FIELDS “17,37,C 1”: “ “ : GOTO 1200&lt;br /&gt;
 01500 PRINT #LP,USING FORMHEADING: TYPE$&lt;br /&gt;
 01600 !&lt;br /&gt;
 01700 ! file processing starts here&lt;br /&gt;
 01800 OPEN #5: “NAME=CHEKBOOK.INT”,INTERNAL,INPUT,SEQUENTIAL&lt;br /&gt;
 01900 !&lt;br /&gt;
 02000 MAINLOOP: READ #5,USING FORM5: DW$ EOF DONE&lt;br /&gt;
 02100 IF DW$&amp;lt;&amp;gt;OPT$ THEN GOTO MAINLOOP&lt;br /&gt;
 02200 REREAD #5,USING FORM5B: AMOUNT,DWDATE&lt;br /&gt;
 02300 PRINT #LP,USING FORMITEM: DWDATE,AMOUNT&lt;br /&gt;
 02400 LET N=N+1&lt;br /&gt;
 02500 LET TOTAL=TOTAL+AMOUNT&lt;br /&gt;
 02600 GOTO MAINLOOP&lt;br /&gt;
 02700 !&lt;br /&gt;
 02800 ! end-of-file processing&lt;br /&gt;
 02900 DONE: CLOSE #5:&lt;br /&gt;
 03000 PRINT #LP,USING FORMTOTAL: N,TYPE$,TOTAL&lt;br /&gt;
 03100 STOP&lt;br /&gt;
 03200 !&lt;br /&gt;
 03300 ! form statements used above&lt;br /&gt;
 03400 FORM5: FORM POS 16,C 1&lt;br /&gt;
 03500 FORM5B: FORM X 5,N 10.2,X 1,N 6&lt;br /&gt;
 03600 FORMHEADING: FORM POS 20,”List of entire checkbook “,C 20,SKIP 2,POS 36,C 8,SKIP 3&lt;br /&gt;
 03700 FORMITEM: FORM POS 30,PIC(Z#/##/##),POS 50, PIC($Z,ZZZ,ZZZ.##)&lt;br /&gt;
 03800 FORMTOTAL: FORM POS 49,”--------------“,SKIP 1,POS 12,N 5,X 2,C 13,”for a total of”,X 4,PIC($Z,ZZZ,ZZZ.##)&lt;br /&gt;
&lt;br /&gt;
Lines 700 to 1200 ask whether the report should include deposits or withdrawals. There is also a third option, to end the program without doing either one. If anything other than one of these three is selected, the program ignores the input and goes back for another choice (see line 1400). The 3-choice screen looks like this:&lt;br /&gt;
&lt;br /&gt;
[[image:14.2.jpg|650px]]&lt;br /&gt;
&lt;br /&gt;
To make the program more “user-friendly”, Business Rules! allows the report choice to be made with just one keystroke. Single-key input is accomplished with the control attributes “ae” in the INPUT FIELDS statement in line 1200.&lt;br /&gt;
&lt;br /&gt;
A second aspect of “user-friendly” input is that both uppercase and lowercase letters are allowed, using the UPRC$ function to convert any lowercase letters to uppercase before the three tests in line 1400. (The opposite of the UPRC$ function is LWRC$.)&lt;br /&gt;
&lt;br /&gt;
Line 1400 uses a single IF-THEN-ELSE statement to process four possible choices. The four possible cases for operator response are: “E”, “D”, “W” and everything else. Schematically, the structure of this statement could be described as IF-THEN-ELSEIF-ELSEIF-ELSE.&lt;br /&gt;
&lt;br /&gt;
Line 1400 tests first for the “E” or end option. If “E” is selected, the program prints the message “Program Complete” on the screen, then a blank line, and then stops. If either of the tests for “D” or “W” are true, the program sets the variable TYPE$ to “Deposits” or “Withdrawals”, respectively. If none of the first three tests are true, the final ELSE clause erases the operator’s response and branches to line 1200 to wait for another response. Only for a response of “D” or “W” will the program continue with line 1500 where a heading is printed for the report.&lt;br /&gt;
&lt;br /&gt;
If either of the tests for “D” or “W” are true, the program continues processing. Line 1800 opens the file, and lines 2000 to 2600 form the major loop of the program. Line 2000 reads the “D” or “W” in the third field of each record and assigns it to a variable called DW$. The FORM statement with the line label FORM5 (located in line 3400) tells the READ statement that the value for DW$ must come from the single character in position 16.&lt;br /&gt;
&lt;br /&gt;
Line 2100 compares the value of DW$ to the value of OPT$, which represents the operator’s choice about which type of records should be included in the report. If the two values are not equal, the record will be skipped. The GOTO MAINLOOP at the end of line 2100 ends processing for mismatching records because it sends the program back to the READ statement to begin processing the next record.&lt;br /&gt;
&lt;br /&gt;
How does the program get out of this loop from 2000 to 2600? The EOF condition on the end of line 2000 will eventually send control to the line label DONE at line 2900. Should the REREAD statement have an EOF clause too? No. It’s impossible for REREAD to encounter an end-of-file condition because it must always follow a successful READ or REREAD--and the READ statement will not be successful unless there is a record to read.&lt;br /&gt;
&lt;br /&gt;
The REREAD statement is especially useful in cases like the LISTDORW program where only certain records are being selected. Another situation where REREAD statements come in handy is when different types of records should be read in different ways. As an example, consider a program that is designed to print date and check number for all withdrawals. In both cases, the system could be designed to determine the type of transaction (“D” or “W”) with the READ statement; program execution could then be branched to the appropriate REREAD statement, each of which would require its own FORM statement.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.6====&lt;br /&gt;
True or False:&amp;lt;br&amp;gt;&lt;br /&gt;
1. The REREAD statement allows you to read a record that has just been read.&lt;br /&gt;
&lt;br /&gt;
2. You can speed up your programs by using the REREAD statement when selecting records instead of a READ statement for all fields in the record.&lt;br /&gt;
&lt;br /&gt;
3. The EOF error sometimes occurs on REREAD statements.&lt;br /&gt;
&lt;br /&gt;
4. Several REREAD statements could be executed consecutively without an error.&lt;br /&gt;
&lt;br /&gt;
5. After the Business Rules! system reads a record, the record stays in a memory buffer until when?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Until the next READ statement is executed.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Until the record is deleted.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Until the next I/O statement is executed.&lt;br /&gt;
&lt;br /&gt;
6. Which Business Rules! function changes all string input to uppercase letters?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) UPRC$&amp;lt;br&amp;gt;&lt;br /&gt;
b) UPCASE$&amp;lt;br&amp;gt;&lt;br /&gt;
c) UPRCL$&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.6]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.7 Deleting records===&lt;br /&gt;
The DELETE statement is used to remove a record from an internal file. The file must already be opened for OUTIN. The syntax is as follows:&lt;br /&gt;
&lt;br /&gt;
 DELETE #file-num, REC=numeric expression, RESERVE: error-condition line ref&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 DELETE #file-num, KEY=string expression, RELEASE: error-condition line ref&lt;br /&gt;
&lt;br /&gt;
The file number of the file from which the record is to be deleted must be identified with the &amp;quot;#file-num&amp;quot; parameter.&lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;REC=num-expr&amp;quot; clause is used with internal files opened for relative or keyed processing, or with external files opened for relative processing. After the numeric expression (usually a simple numeric variable or constant) is evaluated to an integer, the system performs an implied read and the record with that record number is deleted.  The REC= parameter may be used with files opened for either relative or keyed processing; using REC= in this manner will not disturb the key position in the file.  &lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;KEY=string-expr&amp;quot; clause is used with files opened for keyed processing; after the string expression is evaluated (usually a simple string variable or constant), the system performs an implied read and that record is deleted. &lt;br /&gt;
&lt;br /&gt;
If neither “REC=num-expr” (for files opened for RELATIVE access) nor “KEY=string-expr” (for KEYED access) is specified, the record deleted will always be the last one read.  Note: you cannot specify a KEY for RELATIVE-access files.  For SEQUENTIAL processing, the record deleted is always the last record that was read. After DELETE, the next record read will be the next active record after the deleted record. On the other hand, when deleting the record that was just read, you should not use the REC= or KEY= clauses, since they will just generate an unnecessary READ that slows down programs, especially with KEYED processing.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; DELETE must delete exactly one record when it is used. Therefore, in the KEY=n$ clause, the only form allowed is KEY=n$. KEY&amp;gt;=n$, SEARCH=n$, and SEARCH&amp;gt;=n$ are not allowed, as each of these can return 0 records or more than one record, whereas DELETE must delete exactly one record when it is used. (SEARCH and &amp;gt; are used to list files containing specified parts)&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;RESERVE&amp;quot; and &amp;quot;RELEASE&amp;quot; parameters specify record locking rules for multi-user systems. The default is that records are locked when they are read, and released when they are written. (So that if one person is accessing and editing a file, another person can’t READ and change it at the same time). RESERVE and RELEASE can change this default when desired by the programmer. &amp;quot;RESERVE&amp;quot; instructs the system to hold all previous locks and lock the current record. Locked records cannot be read.  &amp;quot;RELEASE&amp;quot; releases all locks and unlocks the current record. &lt;br /&gt;
&lt;br /&gt;
When DELETE is used, the record disappears but its space is not reclaimed automatically. If you want to reclaim that space, the easiest way to do this is using the COPY command with the -D option. (Basically copying the whole file but omitting deleted records). But when doing this, you must rebuild all indexes for that file because the COPY is likely to change relative record numbers, making the index file entries invalid. (Indexing is a way to organize your files).&lt;br /&gt;
&lt;br /&gt;
The positional parameters FIRST, LAST, PRIOR, NEXT, and SAME can be used with the DELETE statement to specify which record to delete from an opened file. These positional parameters can also be used with READ, RESTORE and REWRITE statements. For example:&lt;br /&gt;
&lt;br /&gt;
 DELETE NEXT&lt;br /&gt;
&lt;br /&gt;
The DELETE statement may be used to delete any anchor record or subrecord from a linked list. The DELETE statement must be preceded by a successful READ of the record to be deleted.&lt;br /&gt;
&lt;br /&gt;
Business Rules! will automatically update the next and previous record pointers (held in the first eight bytes of each linked record) of the affected records when a linked list record is deleted. If a linked list&#039;s anchor record is deleted, the next record in the list will become the anchor record. Also, the value of KREC will be updated to return the value of this new anchor record, no matter where the file pointer is in the list.&lt;br /&gt;
&lt;br /&gt;
===Using the REWRITE statement to change information in a file===&lt;br /&gt;
A slightly more complex task in sequential file processing is updating records, making changes to information that is already in a file.&lt;br /&gt;
&lt;br /&gt;
This job requires a combined effort from the READ statement (which finds the information to be changed) and the REWRITE statement (which performs the actual change).&lt;br /&gt;
&lt;br /&gt;
REWRITE is similar to REREAD in that it must follow a successful READ or REREAD statement before any other I/O statement is used. Unlike the REREAD statement, REWRITE statements cannot follow each other. A record can only be rewritten once for each time that it is read.&lt;br /&gt;
&lt;br /&gt;
To illustrate using the REWRITE statement, let’s look at an example of a program for Checkbook Reconciliation. When your bank statement comes, you need to compare your checkbook records to the bank’s records and resolve any differences--a process called reconciliation. At the beginning of the program the operator enters the date of the bank statement, which will later be output to the file for each record that has been cleared by the bank. This program reads each record (that is, looks at each check); it skips over checks and withdrawals that have already cleared (have a non-zero date cleared); then it rereads records that have not been cleared, and displays them on the screen.&lt;br /&gt;
&lt;br /&gt;
For each record displayed on the screen, the operator types Y or N for either “YES, this record has been cleared by the bank” or “NO, this record has not yet cleared the bank” (and needs to be considered outstanding until the next bank statement comes). When the operator says N, the program does not change this record, but goes on to get the next record. When the operator says Y, the program rewrites the record with a new date in the field for date cleared. Finally, the program goes on to read the next record. The program continues in this loop until the end of the file is reached, and then it displays the total number and total amount of deposits and withdrawals that have been cleared in this session.&lt;br /&gt;
&lt;br /&gt;
Here is the listing for the program, called RECONCYL:&lt;br /&gt;
&lt;br /&gt;
 00100 ! ********************** R E C O N C Y L *********************&lt;br /&gt;
 00200 ! PURPOSE: Reconcile bank statement and write date cleared.&lt;br /&gt;
 00300 ! CREATION DATE: 7/23/04 LAST REVISION: 8/21/04&lt;br /&gt;
 00400 ! Business Rules!.&lt;br /&gt;
 00500 ! ************************************************************&lt;br /&gt;
 00600 !&lt;br /&gt;
 00700 ! Get date of bank statement&lt;br /&gt;
 00800 PRINT NEWPAGE&lt;br /&gt;
 00900 PRINT FIELDS “10,26,C 30”: “Enter DATE from Bank Statement”&lt;br /&gt;
 01000 PRINT FIELDS “13,36,C 8”: DATE$(4:8)&amp;amp;”/”&amp;amp;DATE$(1:2) ! CHANGE TO MM/DD/YY&lt;br /&gt;
 01100 INPUT FIELD “13,36,pic(##/##/##),r”: BANKDATE&lt;br /&gt;
 01200 LET BANKDATE= FNYMD(BANKDATE)&lt;br /&gt;
 01300 !&lt;br /&gt;
 01400 ! Setup arrays for full screen processing&lt;br /&gt;
 01500 DIM PFDEFN$(8)*15,DFDEFN$(6)*25,PROMPT$(8)*16,PAYEE$*25&lt;br /&gt;
 01600 LET PFDEFN$(1)=”6,20,C 13”&lt;br /&gt;
 01700 LET PFDEFN$(2)=”8,20,C 13”&lt;br /&gt;
 01800 LET PFDEFN$(3)=”10,20,C 13”&lt;br /&gt;
 01900 LET PFDEFN$(4)=”12,20,C 13”&lt;br /&gt;
 02000 LET PFDEFN$(5)=”14,20,C 13”&lt;br /&gt;
 02100 LET PFDEFN$(6)=”15,20,C 13”&lt;br /&gt;
 02200 LET PFDEFN$(7)=”17,17,C 16,b”&lt;br /&gt;
 02300 LET PFDEFN$(8)=”18,30,C 3,b”&lt;br /&gt;
 02400 LET PROMPT$(1)=”Check Number:”&lt;br /&gt;
 02500 LET PROMPT$(2)=” Date:”&lt;br /&gt;
 02600 LET PROMPT$(3)=” Payee:”&lt;br /&gt;
 02700 LET PROMPT$(4)=” Amount:”&lt;br /&gt;
 02800 LET PROMPT$(5)=”D=Deposit or”&lt;br /&gt;
 02900 LET PROMPT$(6)=”Withdrawal”&lt;br /&gt;
 03000 LET PROMPT$(7)=”Clear this item?”&lt;br /&gt;
 03100 LET PROMPT$(8)=”Y/N”&lt;br /&gt;
 03200 LET DFDEFN$(1)=”6,36,N 5,u”&lt;br /&gt;
 03300 LET DFDEFN$(2)=”8,36,PIC(Z#/##/##),u”&lt;br /&gt;
 03400 LET DFDEFN$(3)=”10,36,C 25,u”&lt;br /&gt;
 03500 LET DFDEFN$(4)=”12,36,PIC(Z,ZZZ,ZZZ.##),u”&lt;br /&gt;
 03600 LET DFDEFN$(5)=”14,36,C 1,u”&lt;br /&gt;
 03700 LET DFDEFN$(6)=”18,36,C 1,r”&lt;br /&gt;
 03800 !&lt;br /&gt;
 03900 OPEN #5: “name=CHEKBOOK.INT”,INTERNAL,OUTIN,SEQUENTIAL&lt;br /&gt;
 04000 !&lt;br /&gt;
 04100 MAINLOOP: READ #5,USING FORM5: DATE_CLEARED EOF DONE&lt;br /&gt;
 04200 IF DATE_CLEARED&amp;lt;&amp;gt;0 THEN GOTO MAINLOOP&lt;br /&gt;
 04300 REREAD #5,USING FORM5B: CHECKNUM,AMOUNT,DW$,CHECKDATE,PAYEE$&lt;br /&gt;
 04400 PRINT NEWPAGE&lt;br /&gt;
 04500 PRINT FIELDS MAT PFDEFN$: MAT PROMPT$&lt;br /&gt;
 04600 PRINT FIELDS MAT DFDEFN$: CHECKNUM,CHECKDATE,PAYEE$,AMOUNT, DW$,”N”&lt;br /&gt;
 04700 INPUT FIELDS DFDEFN$(6): YESNO$&lt;br /&gt;
 04800 LET YESNO$=UPRC$(YESNO$)&lt;br /&gt;
 04900 IF YESNO$=”N” THEN GOTO MAINLOOP !:&lt;br /&gt;
 ELSE IF YESNO$&amp;lt;&amp;gt;”Y” THEN PRINT FIELDS DFDEFN$(6): “ “ : GOTO 4700&lt;br /&gt;
 05000 REWRITE #5,USING FORM5: BANKDATE&lt;br /&gt;
 05100 IF DW$=”D” THEN LET DTOTAL=DTOTAL+AMOUNT: LET NDEPS=NDEPS + 1 !:&lt;br /&gt;
 ELSE LET WTOTAL=WTOTAL+AMOUNT: LET NWDRAWS=NWDRAWS+1&lt;br /&gt;
 05200 GOTO MAINLOOP&lt;br /&gt;
 05300 !&lt;br /&gt;
 05400 ! End-of-file processing&lt;br /&gt;
 05500 DONE: CLOSE #5:&lt;br /&gt;
 05600 PRINT NEWPAGE;”Totals for Bank Statement”&lt;br /&gt;
 05700 PRINT&lt;br /&gt;
 05800 PRINT USING FORMTOTAL: NDEPS,”Deposits”,DTOTAL&lt;br /&gt;
 05900 PRINT USING FORMTOTAL: NWDRAWS,”Withdrawls”,WTOTAL&lt;br /&gt;
 06000 STOP&lt;br /&gt;
 06100 !&lt;br /&gt;
 06200 ! Function for date conversion MMDDYY to YYMMDD&lt;br /&gt;
 06300 DEF FNYMD(X)=(X-INT(X/10000)*10000)*100+INT(X/10000)&lt;br /&gt;
 06400 !&lt;br /&gt;
 06500 ! Form statements used above&lt;br /&gt;
 06600 FORM5: FORM POS 23,N 6&lt;br /&gt;
 06700 FORM5B: FORM N 5,N 10.2,C 1,N 6,X 6,C 25&lt;br /&gt;
 06800 FORMTOTAL: FORM N 5,X 1,C 11,” For a total of”,PIC($,$$Z,ZZZ.##),SKIP 2&lt;br /&gt;
&lt;br /&gt;
As the remarks indicate, lines 800 to 1400 ask the operator for the date of the bank statement. Lines 1700 to 3900 set up arrays to be used later for full-screen processing.&lt;br /&gt;
&lt;br /&gt;
In line 1000, the system variable DATE$, which contains the current system date, is used as an approximation to the date on the bank statement. Because the system date is a string in YYMMDD format, line 1000 uses substring and concatenation capabilities to change the date to MM/DD/YY format.&lt;br /&gt;
&lt;br /&gt;
Line 1200 calls a user-defined function FNYMD to convert the numeric date entered from YYMMDD format to MMDDYY format on the screen. User-defined functions can be placed anywhere in the program. FNYMD is located in line 6300.&lt;br /&gt;
&lt;br /&gt;
Line 3900 opens the file and assigns a file number of 5. To make changes to existing records in a sequential file, the file must be opened OUTIN. To remember this, it might help to think of updating as first inputting the old information, and then outputting the new information.&lt;br /&gt;
&lt;br /&gt;
The main processing loop starts in line 4100 and ends in line 5200. Lines 4100 to 4300 in this program are similar to lines 2000 to 2200 in the LISTDORW program that you studied earlier. Line 4100 reads the minimal information needed to find out if this record should be processed further. Line 4200 tests the information read by line 4100. In this case, the test is whether the field for date cleared has been set to a value other than zero.&lt;br /&gt;
&lt;br /&gt;
If this date is not zero, this record has already cleared the bank, so the program goes back to the start of the loop to read the next record.&lt;br /&gt;
&lt;br /&gt;
For records that have not already cleared the bank, the REREAD statement in line 4300 gets values for the other fields in this record so that the record can be displayed on the screen by the statements in lines 4400 to 4600. Here is the screen which asks the operator whether or not to clear this item.&lt;br /&gt;
&lt;br /&gt;
 Check Number: 12345&lt;br /&gt;
 &lt;br /&gt;
 Date: 10/22/12&lt;br /&gt;
 &lt;br /&gt;
 Payee: Corner Grocery Store&lt;br /&gt;
 &lt;br /&gt;
 Amount: 1,334.44&lt;br /&gt;
 &lt;br /&gt;
 D=Deposit or&lt;br /&gt;
 W=Withdrawal&lt;br /&gt;
 &lt;br /&gt;
 Clear this item?&lt;br /&gt;
 Y/N N&lt;br /&gt;
&lt;br /&gt;
 INPUT&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Again, like the LISTDORW program earlier in this chapter, the operator’s response is forced to be uppercase by line 4800. Line 4900 is an IF statement to consider three different possible operator responses: Y, N or something else. If the operator enters N, this item should not be cleared. If the first test in this IF statement indicates the operator entered N, the program does not rewrite anything, but just goes back to process the next record.&lt;br /&gt;
&lt;br /&gt;
The next case to be considered is when the operator’s reply is neither Y or N. Since the first part of the line has already called out all N responses, the second half of line 4900 needs only to determine that the response was not Y. If it does determine this, then the operator must have entered some other unexpected response. To give the operator another chance at answering the question properly, the input field is erased by writing a blank space on top of the old response, and then the program goes back to the INPUT FIELDS statement in line 4700.&lt;br /&gt;
&lt;br /&gt;
If the operator did enter Y, the program falls through all the parts of line 4900 to line 5000 where it rewrites the record so that the field for date cleared contains the date of the current bank statement. In line 5100, the program totals and counts the value of deposits and withdrawals separately. Line 5300 sends the program back to the start of the main loop to process the next record.&lt;br /&gt;
&lt;br /&gt;
FORM5 (found in line 6600) is the FORM statement used by the REWRITE statement in line 5000. Notice that FORM5 only refers to positions 23-28. It is important to know that the REWRITE statement does not change the other positions in the record. Only positions 23-28 are changed.&lt;br /&gt;
&lt;br /&gt;
When the end of the file is reached, the number of deposits and withdrawals are printed along with their total dollar values.&lt;br /&gt;
&lt;br /&gt;
Do you see any weaknesses in the way this program is designed? Think about what the program does when it reaches the end of the file. Try to come up with something yourself before reading the next paragraph.&lt;br /&gt;
&lt;br /&gt;
If the totals for the computer checkbook do not match the totals for the bank, what choices does the operator have? None! The CHEKBOOK.INT file is immediately changed each time the operator types Y, and there is no way in this program to undo what is done. So if the operator accidentally types Y instead of N even once, there is no way to correct the mistake. If the operator types N instead of Y, the program could be run again, but then the totals on the bank statement would not agree with the computer totals (but hopefully the two sets of computer totals could be added by hand to get the totals from the bank statement).&lt;br /&gt;
&lt;br /&gt;
Programs should not be designed so that the operator is required to never make even one mistake. Programs which do not allow any way to correct mistakes are called “unforgiving”. One characteristic of programs which are “user-friendly” is that they are forgiving.&lt;br /&gt;
&lt;br /&gt;
How could the above program be made forgiving? It would need to allow operators to change their minds about which checks have or have not cleared. This requires that the changes to individual records be temporary; there must be some way to get certain records--perhaps even the entire file--back to the way it was when the program started. There are several ways to do this. You could add another field to the record to indicate which fields are to be changed temporarily. Or you could change the rules for how the field for date cleared is processed, so that it can have temporary values (for example, only write the month and day, then add the year only after the totals have been accepted). The example program did not include any of these provisions, because it would make it harder for you to read and understand the main points; now that you see the big picture, it would be good for you to modify the program to be forgiving.&lt;br /&gt;
&lt;br /&gt;
Another way to make the program forgiving would be to copy the original file to a temporary file, and then make all the changes on the temporary file. If the totals at the end are not correct, then the program would erase the copy and keep the original file. If the totals are correct, the original file would be erased, and the temporary file would be renamed to become the corrected new CHEKBOOK.INT file. This method would be easy to code using Business Rules! commands and Business Rules!’s EXECUTE statement. Add these 7 statements. &lt;br /&gt;
&lt;br /&gt;
 03850 EXECUTE “COPY CHEKBOOK.INT CHEKBOOK.BAK”&lt;br /&gt;
 05910 PRINT “Are these totals correct?”&lt;br /&gt;
 05920 LINPUT YESNO$&lt;br /&gt;
 05930 YESNO$=LTRM$(YESNO$(1:1))&lt;br /&gt;
 05940 IF YESNO$=”Y” OR YESNO$=”y” THEN STOP&lt;br /&gt;
 05950 EXECUTE “FREE CHEKBOOK.INT”&lt;br /&gt;
 05960 EXECUTE “RENAME CHEKBOOK.BAK CHEKBOOK.INT”&lt;br /&gt;
 05970 PRINT “Original file restored. Run program again.” &lt;br /&gt;
&lt;br /&gt;
Line 4050 makes a backup copy of the file before it is opened in line 4100. Changes are made on the original file. After the totals are displayed in lines 5800 and 5900, the operator is asked if the totals are correct by the new lines 5910 and 5920. (If the operator’s response does not start with the letter Y.)&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.7====&lt;br /&gt;
1. The purpose of the REWRITE statement is:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) To add new records to a file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) To change existing records in a file.&amp;lt;br&amp;gt;&lt;br /&gt;
c) To prevent plagiarism.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. To use the REWRITE statement, a file must be opened with the keyword:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) INPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
b) OUTPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
c) OUTIN.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. When a REWRITE statement updates one field in the record, fields in the record which are not specified in the associated FORM statement:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Will be changed to blank spaces.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Will remain unchanged.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Will automatically be listed on the screen.&lt;br /&gt;
&lt;br /&gt;
4. With files opened for sequential processing, the REWRITE statement can only make changes to:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) The first record in the file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) The last record read.&amp;lt;br&amp;gt;&lt;br /&gt;
c) The last record deleted.&amp;lt;br&amp;gt;&lt;br /&gt;
d) The next record pointed to by the file pointer.&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.7]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.8 More about OUTPUT, INPUT and OUTIN===&lt;br /&gt;
You have now opened the CHEKBOOK.INT file in three different ways: for OUTPUT of information to a file; for INPUT of information from a file; and for both output to and input from the file (with OUTIN). Let’s consider each of these types of file use in more detail.&lt;br /&gt;
&lt;br /&gt;
;OUTPUT&lt;br /&gt;
Files should be opened for OUTPUT whenever you plan to only add new information to the file. OUTPUT implies that no information will be read from the file, and no existing information will be changed. Files opened for output may use the WRITE, DELETE and RESTORE I/O statements. The Business Rules! system does not allow the use of READ, REREAD or REWRITE statements on files which are open for output.&lt;br /&gt;
&lt;br /&gt;
;INPUT&lt;br /&gt;
Files should be opened for INPUT whenever the file will only be read, for example, in a program to print a report. INPUT implies that no new information will be added to the file, and none of the current information in the file will be changed. Files which are opened for input may use the READ, REREAD and RESTORE statements, but the Business Rules! system does not allow the use of DELETE, WRITE or REWRITE statements on files open for input.&lt;br /&gt;
&lt;br /&gt;
;OUTIN&lt;br /&gt;
OUTIN allows both input and output. It must be used when you wish to change information that already exists in the file. Files which are opened for outin may use all six of the I/O statements.&lt;br /&gt;
&lt;br /&gt;
After reading each of these descriptions, you may think that it’s a good idea to always code OUTIN if you are not sure how a file will be used. Especially for multi-user systems, however, this is not a good idea because it can increase system overhead. Also, other programmers expect a program to change a file when the OPEN statement specifies OUTIN. If your programs instead use OUTIN at random, they will be difficult and confusing for others to read. It is better to decide what is needed in the OPEN statement and code exactly what is needed. Also, this prevents accidentally writing or rewriting to a file by mistake (since a file opened for INPUT will throw an error if you attempt to write to it).&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.8====&lt;br /&gt;
1. A program that reads information in a file without changing it should specify which type of use in the OPEN statement?&amp;lt;br&amp;gt;&lt;br /&gt;
a) INPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
b) OUTPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
c) OUTIN.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2.  A program that changes information in a file should specify which type of use in the OPEN statement?&amp;lt;br&amp;gt;&lt;br /&gt;
a) INPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
b) OUTPUT.&amp;lt;br&amp;gt;&lt;br /&gt;
c) OUTIN.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.8]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===14.9 The file pointer and the RESTORE statement===&lt;br /&gt;
Remember Zippy’s trusty friend the File Pointer? This diligent worker always keeps careful track of the next record to be accessed in an open data file. As a programmer, you must be aware of how the File Pointer operates so that you can predict which record will be accessed next.&lt;br /&gt;
&lt;br /&gt;
With sequential file processing, it is fairly simple to figure out which record will be accessed next because the file pointer always moves through the file sequentially, or one record at a time. With relative or keyed access, the file pointer starts where specified in the statement.&lt;br /&gt;
&lt;br /&gt;
Depending on how the file is opened, the file pointer starts out at either the beginning or end of a file that is to be sequentially processed. The file pointer always goes to the first record in the file when the OPEN statement specifies either INPUT,SEQUENTIAL or OUTIN,SEQUENTIAL. If you ever want to send the file pointer back to the beginning of the file to start accessing the same records all over again, you can use the RESTORE statement.&lt;br /&gt;
&lt;br /&gt;
RESTORE is one of the six I/O statements; when used with sequential processing, its syntax requires only the file number of the file to be restored. As an example of using RESTORE, imagine that you have opened CHEKBOOK.INT for sequential processing, but you are only interested in processing the first 20 withdrawal records. (Your program can use a counter variable to keep track of the number of times that the system completes the processing loop; when the value of the variable is 20, then you have processed the first 20 records.) Once this is done, you instruct the program to determine the average amount of each of the 20 checks. You then want it to go back to the beginning of the file and reprocess only those checks that were written for an amount that exceeds the average. The use of the RESTORE statement would cause the file pointer to move back to the beginning of the file even if it’s only half way through (rather than at the end) of the file at the time.&lt;br /&gt;
&lt;br /&gt;
An example of RESTORE when used in this situation could be:&lt;br /&gt;
&lt;br /&gt;
 7600 RESTORE #4:&lt;br /&gt;
&lt;br /&gt;
When OUTPUT,SEQUENTIAL is specified in the OPEN statement, the File Pointer knows that you probably want to add records to the end of the file--so he immediately positions himself after the last record. In case he was wrong about his prediction, the RESTORE statement can again be used to reposition the pointer at the beginning of the file. However, RESTORE used on a file opened OUTPUT,SEQUENTIAL will cause all existing records in the file to be erased. After a RESTORE on a file opened for output, the pointer is sitting at the beginning of an empty file. That’s good news if you wanted an empty file, but sometimes it can be bad news. Be careful with the RESTORE statement.&lt;br /&gt;
&lt;br /&gt;
The following two statements would open an imaginary data file called SALESCAL.INT for output of new records, and then empty the file of all existing records (same as a DROP command).&lt;br /&gt;
&lt;br /&gt;
 500 OPEN #5: “NAME=SALESCAL.INT”, INTERNAL,OUTPUT,SEQUENTIAL&lt;br /&gt;
 600 RESTORE #5:&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 14.9====&lt;br /&gt;
Fill in each of the banks below with either “beginning” or “end”:&lt;br /&gt;
&lt;br /&gt;
a) When a file is opened INPUT,SEQUENTIAL, the pointer is positioned at the _____________ of the file.&amp;lt;br&amp;gt;&lt;br /&gt;
b) When a file is opened OUTPUT,SEQUENTIAL, the pointer is positioned at the _____________ of the file.&amp;lt;br&amp;gt;&lt;br /&gt;
c) When a file is opened OUTIN,SEQUENTIAL, the pointer is positioned at the _____________ of the file.&amp;lt;br&amp;gt;&lt;br /&gt;
d) The purpose of the RESTORE statement is to move the pointer to the _____________ of the file.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. To be able to read sequentially from an internal file, the best way to code the OPEN statement is:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) DISPLAY, OUTIN, SEQUENTIAL&amp;lt;br&amp;gt;&lt;br /&gt;
b) INTERNAL, OUTPUT, RELATIVE&amp;lt;br&amp;gt;&lt;br /&gt;
c) INTERNAL, INPUT, SEQUENTIAL&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. True or False: The best way to add records to the end of a long data file for OUTPUT,SEQUENTIAL, then use the RESTORE statement.&lt;br /&gt;
&lt;br /&gt;
[[Answers 14.9]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
NEXT:[[Chapter 15|The RELATIVE method of access for INTERNAL files]]&lt;br /&gt;
&lt;br /&gt;
[[BR Tutorial|Back to Index]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Tutorial 1]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_10&amp;diff=10845</id>
		<title>Chapter 10</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_10&amp;diff=10845"/>
		<updated>2017-03-09T18:30:23Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Challenge Question */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===Introduction=== &lt;br /&gt;
This chapter will teach about &#039;&#039;&#039;Arrays&#039;&#039;&#039;.  When you’re done you should be able to: &lt;br /&gt;
*Describe an array, and understand the difference between a one-dimensional and a multi-dimensional array.  (matrixes) &lt;br /&gt;
*Explain the difference between a subscripted and an unsubscripted variable. &lt;br /&gt;
*Explain the purpose of the DIM statement. &lt;br /&gt;
*Perform mathematical operations using arrays. &lt;br /&gt;
*Print an array using nested FOR/NEXT loops &lt;br /&gt;
 &lt;br /&gt;
===10.1 Introduction to one-dimensional Arrays===&lt;br /&gt;
Imagine a situation where you would want to compare a record of the average monthly temperatures for a year in St. Paul, Minnesota, to those in New York, New York.  A table showing these figures might be as follows: &lt;br /&gt;
&lt;br /&gt;
{|  &lt;br /&gt;
|Month &lt;br /&gt;
|SP &lt;br /&gt;
|NY&lt;br /&gt;
|- &lt;br /&gt;
|January &lt;br /&gt;
|6 &lt;br /&gt;
|27 &lt;br /&gt;
|- &lt;br /&gt;
|February &lt;br /&gt;
|17 &lt;br /&gt;
|37 &lt;br /&gt;
|- &lt;br /&gt;
|March &lt;br /&gt;
|38 &lt;br /&gt;
|52 &lt;br /&gt;
|- &lt;br /&gt;
|April &lt;br /&gt;
|49 &lt;br /&gt;
|69 &lt;br /&gt;
|- &lt;br /&gt;
|May &lt;br /&gt;
|66 &lt;br /&gt;
|73 &lt;br /&gt;
|- &lt;br /&gt;
|June &lt;br /&gt;
|75 &lt;br /&gt;
|84 &lt;br /&gt;
|- &lt;br /&gt;
|July &lt;br /&gt;
|93 &lt;br /&gt;
|92 &lt;br /&gt;
|- &lt;br /&gt;
|August &lt;br /&gt;
|84 &lt;br /&gt;
|83 &lt;br /&gt;
|- &lt;br /&gt;
|September &lt;br /&gt;
|77 &lt;br /&gt;
|79 &lt;br /&gt;
|- &lt;br /&gt;
|October &lt;br /&gt;
|67 &lt;br /&gt;
|78 &lt;br /&gt;
|- &lt;br /&gt;
|November &lt;br /&gt;
|42 &lt;br /&gt;
|50 &lt;br /&gt;
|- &lt;br /&gt;
|December &lt;br /&gt;
|22 &lt;br /&gt;
|43 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Before you could compare these figures within a program, you would need some way to refer to them as variables.  St. Paul’s January temperature could for instance, be assigned to the variable SPJAN, and New York’s January temperature could be NYJAN.  &lt;br /&gt;
&lt;br /&gt;
For example: &lt;br /&gt;
 00010 LET SPJAN=6 &lt;br /&gt;
 00020 LET SPFEB=17 &lt;br /&gt;
 …&lt;br /&gt;
 000150 LET NYJAN=27 &lt;br /&gt;
 000160 LET NYFEB=37&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
When all the variables were assigned, you would have 24 separate variables and 24 different variable names to remember.  Juggling all these variables and their names would eventually become a very clumsy process. &lt;br /&gt;
&lt;br /&gt;
A more convenient way to handle the numbers would be to assign each of the two lists of temperatures to its own variable.  All of the St. Paul temperatures could then be referred to as SPTEMP, and all the New York temperatures could be called NYTEMP.  You would then have two variable names instead of 24 to remember.  Business Rules! calls a list of values such as these an array. If pictured, it would be arranged like this:&lt;br /&gt;
 SPTEMP=6 17 8 49 66 75 93 84 77 67 42 22&lt;br /&gt;
 NYTEMP= 27 37 52 69 73 84 92 83 79 78 50  43 &lt;br /&gt;
&lt;br /&gt;
Once you have assigned a list of values to an array, Business Rules! allows you to refer to each individual value within the list by its position number. For example:&lt;br /&gt;
 SPTEMP (1) = 6 and NYTEMP(6)=84  &lt;br /&gt;
&lt;br /&gt;
St. Paul’s January temperature would then become SPTEMP(1) because it is the first value in the SPTEMP array.  Likewise, New York’s June temperature would be NYTEMP(6).  The position number is called a subscript, and it is always placed in parentheses after the variable name.&lt;br /&gt;
&lt;br /&gt;
===The DIM statement===&lt;br /&gt;
To assign a list of values to an array, you must first tell Business Rules! how many values will be in the list.  This is done with the DIM statement.  The DIM syntax that you would use for our lists of St. Paul and New York’s temperatures is: &lt;br /&gt;
 line# DIM array-name (#of values)   &lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;“array-name”&#039;&#039;&#039; portion of the syntax is the name of the variable you wish to use. (Array variables, which are often referred to as subscripted variables, follow the same naming rules as the unsubscripted variables you have already learned about.) &lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;“(#of values)”&#039;&#039;&#039; portion of the syntax indicates the number of values in the list; this number must be placed within parentheses, and must be an integer number, not a variable. &lt;br /&gt;
  &lt;br /&gt;
You may repeat the “array-name” and “(#rows)” parameters when you wish to dimension more than one array in the same DIM statement, but you must separate each set of specifications with a comma.  As an example, the DIM statement for our St. Paul and New York temperatures example would be as follows:   &lt;br /&gt;
 00050 DIM SPTEMP(12), NYTEMP(12)   &lt;br /&gt;
&lt;br /&gt;
This statement tells Business Rules! to reserve space for twelve values in both the SPTEMP and NYTEMP “manila folders”.  Business Rules! automatically assigns a value of 0 to each element in the array until you explicitly assign another.  &lt;br /&gt;
DIM is a non-executable statement; it can be placed anywhere in a program. This is because Business Rules! automatically checks an entire program for DIM statements before every program execution.  Many programmers like to place all their DIM statements either at the beginning or end of a program for easy reference.&lt;br /&gt;
&lt;br /&gt;
===Assigning values to variables=== &lt;br /&gt;
Once you have used DIM to tell Business Rules! how many values will be assigned to a particular array name, you can go about assigning those values.  The same statements that you used to assign values to unsubscripted variables--LET, INPUT, READ, and DATA--can also be used to assign subscripted variables. The tricky part about assigning values to subscripted variables is that you must assign the right value to the right subscript.  One way to do this is to individually assign values to the subscripted variables with LET statements.  You could go through and assign each value in the following manner for instance:  &lt;br /&gt;
 00070 DIM SPTEMP(12) &lt;br /&gt;
 00080 LET SPTEMP(1)=6 &lt;br /&gt;
 00090 LET SPTEMP(2)=17 &lt;br /&gt;
 00100 LET SPTEMP(3)=38 &lt;br /&gt;
 00110 LET SPTEMP(4)=49 &lt;br /&gt;
 00120 LET SPTEMP(5)=66 &lt;br /&gt;
 00130 LET SPTEMP(6)=75 &lt;br /&gt;
 00140 LET SPTEMP(8)=93 &lt;br /&gt;
 00150 LET SPTEMP(9)=84 &lt;br /&gt;
 00160 LET SPTEMP(10)=77 &lt;br /&gt;
 00170 LET SPTEMP(11)=42 &lt;br /&gt;
 00180 LET SPTEMP(12)=22 &lt;br /&gt;
&lt;br /&gt;
Another way that you could individually assign the values is with the DATA and READ statements:   &lt;br /&gt;
 00070 DIM SPTEMP(12) &lt;br /&gt;
 00080 DATA 6,17,38,49,66,75,93,84,77,67,42,22 &lt;br /&gt;
 00090 READ SPTEMP(1),SPTEMP(2),SPTEMP(3),SPTEMP(4),SPTEMP(5),SPTEMP(6),SPTEMP(8),SPTEMP(9),SPTEMP(10),SPTEMP(11),SPTEMP(12) &lt;br /&gt;
&lt;br /&gt;
As you can probably see, both these methods require a lot of typing and a great deal of repetition.  (And when you start to use a great deal of repetition in programming, it’s usually a sign that there’s an easier and quicker way to do whatever you’re doing!)  One easier and quicker way to assign values to an array is to use a FOR/NEXT loop along with READ and DATA statements.  The following set of program lines assigns the average monthly temperatures for both St. Paul and New York to their respective array variables: &lt;br /&gt;
&lt;br /&gt;
 00070 DIM SPTEMP(12), NYTEMP(12) &lt;br /&gt;
 00079 ! data for sptempt&lt;br /&gt;
 00080 DATA 6,17,38,49,66,75,93,84,77,67,42,22 &lt;br /&gt;
 00089 ! data for nytemp&lt;br /&gt;
 00090 DATA 27,37,52,69,73,84,92,83,79,78,50,43 &lt;br /&gt;
 00100 FOR J=1 TO 12 ! Loop to assign values to SPTEMP &lt;br /&gt;
 00110   READ SPTEMP(J) &lt;br /&gt;
 00120 NEXT J ! Loop to assign values to NYTEMP &lt;br /&gt;
 00130 FOR K=1 TO 12 &lt;br /&gt;
 00140   READ NYTEMP(K) &lt;br /&gt;
 00150 NEXT K &lt;br /&gt;
&lt;br /&gt;
;Because BR can’t handle comments in a DATA statement, they have been placed in the line above each DATA statement.&lt;br /&gt;
&lt;br /&gt;
Let’s follow the execution sequence of this example.  First, Business Rules! takes note of (but does not execute) lines 70 through 90.  Next, it enters the FOR/NEXT loop at line 100.  The READ statement at line 110 instructs Business Rules! to assign a data item to SPTEMP(J). Since this is the first time through the loop, J equals one.&lt;br /&gt;
&lt;br /&gt;
The first available data item, 6, will thus be assigned to the first position in the array, SPTEMP(1).&lt;br /&gt;
&lt;br /&gt;
The second time through the loop, J will equal two.  Thus the next available data item, 17, will be assigned to SPTEMP(2).  This looping process will continue until J is greater than 12.  At that point, Business Rules! will jump to line 130 and right into another loop which conducts the same operation for the array variable NYTEMP.   &lt;br /&gt;
&lt;br /&gt;
Each of the examples in this section has referred only to numeric array variables, but it is also possible to assign string values to string array variables.  The following example, for instance, uses an INPUT statement to assign string values to the array EMPLOYEE$.  &lt;br /&gt;
 00060 DIM EMPLOYEE$(14) &lt;br /&gt;
 00070 FOR X=1 TO 14 &lt;br /&gt;
 00080   PRINT “Enter employee’s name” e&lt;br /&gt;
 00090   INPUT EMPLOYEE$(X) &lt;br /&gt;
 00100 NEXT X &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 10.1====&lt;br /&gt;
&lt;br /&gt;
1. Which of the following definitions best describes an array? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a. A subscripted variable which follows the same naming rules as simple variables. &amp;lt;br&amp;gt;&lt;br /&gt;
b. A list of values which are assigned to the same position within the list. &amp;lt;br&amp;gt;&lt;br /&gt;
c. A programming statement which tells Business Rules! how many values will be assigned to a particular variable. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Which of the following variables are subscripted? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a. JKX(X) &amp;lt;br&amp;gt;&lt;br /&gt;
b. C10 &amp;lt;br&amp;gt;&lt;br /&gt;
c. JKX &amp;lt;br&amp;gt;&lt;br /&gt;
d. C$(10) &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 10.1]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===10.2 Performing comparisons &amp;amp; Arithmetic operations with Arrays=== &lt;br /&gt;
In the last lesson you learned to assign values to one-dimensional arrays. Let’s now use those arrays in some arithmetic operations. &lt;br /&gt;
&lt;br /&gt;
===Arithmetic operations with arrays=== &lt;br /&gt;
Our original intent in the last lesson was to compare the average monthly temperatures between St. Paul and New York; let’s do that now.  To start off, let’s have our program list the difference in average temperatures between the two cities for each month. While we’re at it, we might as well assign this list to a third program array: TEMPDIF.  You might have already guessed that this operation will employ another FOR/NEXT loop: &lt;br /&gt;
&lt;br /&gt;
 00070 DIM SPTEMP(12), NYTEMP(12), TEMPDIF(12) &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 00170 FOR C=1 TO 12 ! Loop to find difference in monthly temps &lt;br /&gt;
 00180   LET TEMPDIF(C)=SPTEMP(C)-NYTEMP(C) &lt;br /&gt;
 00190   PRINT SPTEMP(C),NYTEMP(C),TEMPDIF(C) &lt;br /&gt;
 00200 NEXT C &lt;br /&gt;
&lt;br /&gt;
In the above example, line 180 uses the loop variable to regulate which item in the list is calculated.  The first time through the loop, it calculates the difference between the first items (the January temperatures) in the St. Paul and New York temperature lists.  It then assigns the value of the difference to the first element in the TEMPDIF array.  The second time through the loop, line 180 calculates the difference between the second items in the temperature lists and assigns the difference to the second element of TEMPDIF.  This process continues until the loop variable is greater than 12.   &lt;br /&gt;
&lt;br /&gt;
Notice that values were assigned to TEMPDIF in a slightly different manner here than when we assigned values to the other two arrays.  Instead of placing the values into DATA statements and instructing Business Rules! to READ them, we told Business Rules! to generate the values (from an arithmetic operation with other values) and then immediately place them into an array.  &lt;br /&gt;
 &lt;br /&gt;
Also notice that we went back to the DIM statement in line 70 and added the dimensions for the TEMPDIF array. &lt;br /&gt;
&lt;br /&gt;
===Arithmetic operations within arrays ===&lt;br /&gt;
You’ve now seen how to perform arithmetic operations from the values of one array to the values of another, but it is also possible to perform these operations within arrays.  As an example, let’s imagine that you want to find out the average yearly temperature (based on the average monthly temperatures) for both St. Paul and New York.  To find this information, you must add the twelve values in each array together, and then divide by twelve.  And guess what? You can use a FOR/NEXT loop to do this too!   &lt;br /&gt;
&lt;br /&gt;
 00210 FOR A=1 TO 12 ! Loop to find average yearly temperatures &lt;br /&gt;
 00220   LET SPAV=SPAV+SPTEMP(A) ! SPAV=St. Paul yearly average &lt;br /&gt;
 00230   LET NYAV=NYAV+NYTEMP(A) ! NYAV=New York yearly average &lt;br /&gt;
 00240 NEXT A &lt;br /&gt;
 00250 LET SPAV=SPAV/12 &lt;br /&gt;
 00260 LET NYAV=NYAV/12 &lt;br /&gt;
 00270 PRINT SPAV,NYAV &lt;br /&gt;
&lt;br /&gt;
Now try one for yourself:  What statements should you add to the above set of lines so that it also computes and prints the average yearly difference (based on the average monthly differences contained in the TEMPDIF array) in temperatures between St. Paul and New York? &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 10.2====&lt;br /&gt;
1. The following section of program code should compute and print the average of the six values in the POPCAL array, but it contains a bug.  Can you discover it? &lt;br /&gt;
&lt;br /&gt;
 07000 FOR A=1 TO 6 &lt;br /&gt;
 07010   LET POPAV=POPAV+POPCAL(A) &lt;br /&gt;
 07020   LET POPAV=POPAV/6 &lt;br /&gt;
 07030 NEXT A &lt;br /&gt;
 07040 PRINT POPAV&lt;br /&gt;
&lt;br /&gt;
[[Answer 10.2]]&lt;br /&gt;
&lt;br /&gt;
====Challenge Question====&lt;br /&gt;
The St. Paul/New York temperature comparison program currently prints out three columns of unidentified information.  Using a fourth array (a string array) which contains a list of the months in the year, and using the information that you learned in your chapter on PRINT, make your output look as follows: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|Month &lt;br /&gt;
|SP &lt;br /&gt;
|NY &lt;br /&gt;
|Dif &lt;br /&gt;
|-&lt;br /&gt;
|January &lt;br /&gt;
|6 &lt;br /&gt;
|27 &lt;br /&gt;
| -21 &lt;br /&gt;
|-&lt;br /&gt;
|February &lt;br /&gt;
|17 &lt;br /&gt;
|37 &lt;br /&gt;
| -20 &lt;br /&gt;
|-&lt;br /&gt;
|March &lt;br /&gt;
|38 &lt;br /&gt;
|52 &lt;br /&gt;
| -14 &lt;br /&gt;
|-&lt;br /&gt;
|April &lt;br /&gt;
|49 &lt;br /&gt;
|69 &lt;br /&gt;
| -20 &lt;br /&gt;
|-&lt;br /&gt;
|May &lt;br /&gt;
|66 &lt;br /&gt;
|73 &lt;br /&gt;
| -7 &lt;br /&gt;
|-&lt;br /&gt;
|June &lt;br /&gt;
|75 &lt;br /&gt;
|84 &lt;br /&gt;
| -9 &lt;br /&gt;
|-&lt;br /&gt;
|July &lt;br /&gt;
|93 &lt;br /&gt;
|92 &lt;br /&gt;
| 1 &lt;br /&gt;
|-&lt;br /&gt;
|August &lt;br /&gt;
|84 &lt;br /&gt;
|83 &lt;br /&gt;
| 1 &lt;br /&gt;
|-&lt;br /&gt;
|September &lt;br /&gt;
|77 &lt;br /&gt;
|79 &lt;br /&gt;
| -2 &lt;br /&gt;
|-&lt;br /&gt;
|October &lt;br /&gt;
|67 &lt;br /&gt;
|78 &lt;br /&gt;
| -11 &lt;br /&gt;
|-&lt;br /&gt;
|November &lt;br /&gt;
|42 &lt;br /&gt;
|50 &lt;br /&gt;
| -8 &lt;br /&gt;
|-&lt;br /&gt;
|December &lt;br /&gt;
|22 &lt;br /&gt;
|43 &lt;br /&gt;
| -21 &lt;br /&gt;
|-&lt;br /&gt;
|Yearly  Average &lt;br /&gt;
|53 &lt;br /&gt;
|63.91667 &lt;br /&gt;
| -10.91666 &lt;br /&gt;
|}  &lt;br /&gt;
&lt;br /&gt;
CQ: Compare your program to the program TEMPID on the [[Solutions#CHAPTER 10|Solutions]] page.&lt;br /&gt;
&lt;br /&gt;
===10.3 Using MAT to perform arithmetic with arrays===&lt;br /&gt;
So far we have shown you how to manipulate arrays only in long-hand fashion.  There is still a faster and easier method of handling many array functions however, and that is with the MAT keyword.&lt;br /&gt;
&lt;br /&gt;
In conjunction with READ, the Business Rules! MAT keyword allows you to assign values to an array without using a FOR/NEXT loop.  MAT can also be used as a separate statement to quickly and easily re-dimension, perform arithmetic with, and sort arrays.&lt;br /&gt;
&lt;br /&gt;
===Assigning values to arrays with READ MAT=== &lt;br /&gt;
The simplest way to assign values to a variable is with the DATA and the READ MAT statements.  As an example, let’s assign the values Andrew, Rhonda, Silvia, Jack and Warren to the string array NAME$, and the values 17900, 89500, 26500, 86000 and 47000 to the numeric array SAL:&lt;br /&gt;
&lt;br /&gt;
[[image:10.1.png]]&lt;br /&gt;
&lt;br /&gt;
When used in the READ statement, the MAT keyword tells Business Rules! that it should assign values to an array (which is also sometimes called a matrix).  Business Rules! then checks the size (as indicated in the DIM statement) of the specified array before proceeding to assign values to it in row-by-row order.   &lt;br /&gt;
You can also use the MAT keyword with the PRINT statement to print an array, as in the following example:&lt;br /&gt;
 00070 PRINT MAT NAME$ &lt;br /&gt;
 00080 PRINT MAT SAL   &lt;br /&gt;
&lt;br /&gt;
The above program lines would print the following:&lt;br /&gt;
  &lt;br /&gt;
[[image:10.2.png]]&lt;br /&gt;
&lt;br /&gt;
===Re-dimensioning arrays===&lt;br /&gt;
Let’s imagine that the following table represents the current yearly salaries of five people in your company.  The information in the first column is contained in the one-dimensional array NAME$, and the information in the second column is contained in the one-dimensional array SAL: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|Andrew&lt;br /&gt;
|17900&lt;br /&gt;
|-&lt;br /&gt;
|Rhonda&lt;br /&gt;
|89500&lt;br /&gt;
|-&lt;br /&gt;
|Silvia&lt;br /&gt;
|26500&lt;br /&gt;
|-&lt;br /&gt;
|Jack&lt;br /&gt;
|86000&lt;br /&gt;
|-&lt;br /&gt;
|Warren&lt;br /&gt;
|47000&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Since the SAL array contains five elements, the DIM statement that originally dimensioned it also specifies five elements.  But let’s imagine that now (many program lines and operations after the original DIM statement) you want to add the names of four more employees to the list.  The MAT statement allows you to re-dimension the array so that it will now have room for nine values instead of five.  The syntax of this use of MAT is as follows:&lt;br /&gt;
 line# MAT array-name(#rows) &lt;br /&gt;
&lt;br /&gt;
The MAT statement for our example would then be the following: &lt;br /&gt;
 00980 MAT SAL(9) &lt;br /&gt;
&lt;br /&gt;
===Using MAT to perform arithmetic with arrays===&lt;br /&gt;
Since your company’s policy is that employees get an automatic cost-of-living pay increase in February of each year, you need to find a simple way to compute the new salaries.  This year’s pay increase is 6.4% of the current salary.   &lt;br /&gt;
In addition to allowing you to re-dimension arrays, the MAT statement allows you to add, subtract, multiply or divide each element in an array by another value.  The syntax for MAT in this instance would be:&lt;br /&gt;
 line# MAT array-name = (num-expr or array name) +-*/ array-name  &lt;br /&gt;
&lt;br /&gt;
The first “array-name” is the name of the array to which the new array values should be assigned.&amp;lt;br&amp;gt;&lt;br /&gt;
The equal sign (=) is required. &amp;lt;br&amp;gt;&lt;br /&gt;
The “(num-expr)” portion of the syntax or array name indicates the value that should be applied (added, subtracted, multiplied or divided) to each element in the array.  The numeric expression must be placed within parentheses if it is not an array name. &amp;lt;br&amp;gt;&lt;br /&gt;
The numeric operator, represented by “+-*/” in the above syntax statement, specifies the arithmetic function which is to occur. &amp;lt;br&amp;gt;&lt;br /&gt;
The second “array-name” is the name of the array containing the elements to be manipulated.  This may be the same as the first array name. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following example multiplies each salary in the SAL array by 1.064.  Each of the old values is replaced by the new value.   &lt;br /&gt;
 09870 MAT SAL = (1.064)*SAL   &lt;br /&gt;
To print a listing of the new SAL values, you can use the immediate mode command PRINT MAT SAL after the line above has been executed.&lt;br /&gt;
&lt;br /&gt;
===UDim===&lt;br /&gt;
Often when writing a program, you won’t know how many spaces will be in the array, or you will want to constantly add more lines to the array. For example, in the program above, if the user wanted to add several more employees every month as the company grew, you don’t have to constantly change the size of the array using the MAT statement. Instead, the UDim function can be used to retrieve the current size of the array, for example, to put it into a variable. As you add employee names to the array, it will serve to constantly adjust for those additions without you having to specify the size. &lt;br /&gt;
The syntax for UDim is as follows:&lt;br /&gt;
UDim(array-name) &lt;br /&gt;
&lt;br /&gt;
====Mid-Chapter Practice:====&lt;br /&gt;
1. Use the name and salary chart above for the first five employees. &lt;br /&gt;
2. Modify the program to use a for/next loop to ask for new employees’ names and salaries and add them to the arrays, so that the program will list the names and salaries for all nine employees. Use the UDim function described above.&lt;br /&gt;
3. Then add lines to the program to calculate and list next year’s salaries for each employee. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|George&lt;br /&gt;
|35,200&lt;br /&gt;
|-&lt;br /&gt;
|Leah&lt;br /&gt;
|68,300&lt;br /&gt;
|-&lt;br /&gt;
|Alana&lt;br /&gt;
|43,650&lt;br /&gt;
|-&lt;br /&gt;
|Tim&lt;br /&gt;
|29,870&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The completed program should look something like this (only scroll ahead after you have tried and completed your program): &lt;br /&gt;
[[image:10.3.jpg|600px]]&lt;br /&gt;
&lt;br /&gt;
If you need help with the code itself, check your program against the one listed below:&lt;br /&gt;
[[image:10.4.jpg|600px]]&lt;br /&gt;
&lt;br /&gt;
===Sorting arrays with MAT and the AIDX or DIDX functions===&lt;br /&gt;
Business Rules!’s MAT statement allows you to sort and reorder the elements in an array.  Numeric arrays can be sorted from the lowest element to the highest element with the AIDX function, or they can be sorted from highest to lowest with the DIDX function (AIDX is ascending order; DIDX is descending order; IDX stands for index).  String elements can be sorted in alphabetical order with the AIDX function, or they can be sorted in reverse alphabetical order with the DIDX function.&lt;br /&gt;
&lt;br /&gt;
When sorting array elements with AIDX or DIDX, it’s important to remember that Business Rules! does not change the order of elements in the original array.  Instead, a new array must be named to hold the subscripts of the original array in their sorted (indexed) order. &lt;br /&gt;
&lt;br /&gt;
In the following example, the string array CUST$ holds the last names of five customers.  The numeric array ORDER holds the subscripts of the CUST$ values in their sorted order.  Printing out the actual names in alphabetical order requires the statements in lines 50-70.  The first time through the loop, this statement takes the first element in the ORDER array and makes it the subscript of the element in the CUST$ array to be printed.  The second time through the loop, it uses the second element in the ORDER array as the CUST$ subscript.  The process continues until all elements are printed.  &lt;br /&gt;
[[image:10.5.jpg]]&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 10.3====&lt;br /&gt;
1. Which of the following statements are true about the keyword MAT? &amp;lt;br&amp;gt;&lt;br /&gt;
a. It is a statement keyword. &amp;lt;br&amp;gt;&lt;br /&gt;
b. It always refers to an array. &amp;lt;br&amp;gt;&lt;br /&gt;
c. It allows resizing of arrays. &amp;lt;br&amp;gt;&lt;br /&gt;
d. It can be used within the PRINT statement to print the contents of an array. &amp;lt;br&amp;gt;&lt;br /&gt;
e. It can be used within the READ statement to assign values to array elements. &amp;lt;br&amp;gt;&lt;br /&gt;
f. It provides easy ways to perform arithmetic with arrays. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Which of the following statements contains the proper syntax for assigning values to the TEMPLE$ array? &amp;lt;br&amp;gt;&lt;br /&gt;
a. MAT READ TEMPLE$ &amp;lt;br&amp;gt;&lt;br /&gt;
b. MAT TEMPLE$(3) &amp;lt;br&amp;gt;&lt;br /&gt;
c. READ MAT TEMPLE$ &amp;lt;br&amp;gt;&lt;br /&gt;
d. READ TEMPLE$ &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. What do the AIDX and DIDX functions allow you to do? &amp;lt;br&amp;gt;&lt;br /&gt;
a. Sort the elements of an array in either ascending or descending order. &amp;lt;br&amp;gt;&lt;br /&gt;
b. Change the order of elements in an array so that they occur in either ascending or descending order. &amp;lt;br&amp;gt;&lt;br /&gt;
c. Exchange the contents of one array for the contents of another. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 10.3]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===10.4 Two-dimensional matrices===&lt;br /&gt;
You learned in a previous lesson that you can print two or more arrays side-by-side to create a table of information.  Business Rules! also allows you to put all the same information into a single two-dimensional matrix which contains both rows and columns.  The following table for example, comes from the two-dimensional matrix POWERS:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|1 &lt;br /&gt;
|1 &lt;br /&gt;
|1 &lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|2 &lt;br /&gt;
|4 &lt;br /&gt;
|8 &lt;br /&gt;
|16 &lt;br /&gt;
|-&lt;br /&gt;
|3 &lt;br /&gt;
|9 &lt;br /&gt;
|27 &lt;br /&gt;
|81 &lt;br /&gt;
|-&lt;br /&gt;
|4 &lt;br /&gt;
|16 &lt;br /&gt;
|64 &lt;br /&gt;
|256 &lt;br /&gt;
|-&lt;br /&gt;
|5 &lt;br /&gt;
|25 &lt;br /&gt;
|125 &lt;br /&gt;
|625 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
As with one-dimensional matrices or arrays, the values in a two-dimensional matrix are referred to by their position within the matrix.  The difference is that each value in a two-dimensional matrix has both a row and a column position.  &lt;br /&gt;
&lt;br /&gt;
In the above table, the value 2 is located in row 2, column 1.  In terms that Business Rules! understands, its position is POWERS(2,1).  Likewise, the value 81--which is located in row 3, column 4--is POWERS(3,4).&lt;br /&gt;
&lt;br /&gt;
Rows are always specified before columns in Business Rules!.  Keeping this in mind, can you identify the value of POWERS(5,3)?&lt;br /&gt;
&lt;br /&gt;
Two-dimensional matrices are often referred to by their size, or dimensions.  Our example above is a 5X4 array because it is five rows deep by four columns wide.  (Again, rows are always specified first; a 5X4 matrix is different from a 4X5 matrix.)&lt;br /&gt;
&lt;br /&gt;
===Two-dimensional matrices and the DIM statement===&lt;br /&gt;
The DIM statement works in much the same way for a two-dimensional matrix as it does for a one-dimensional matrix (arrays).  The syntax is as follows:   &lt;br /&gt;
line# DIM array-name (#rows,#columns) &lt;br /&gt;
&lt;br /&gt;
The “#rows” portion of the syntax indicates the total number of horizontal rows in the table.  It must be an integer&lt;br /&gt;
&lt;br /&gt;
The “#columns” portion of the syntax indicates the total number of vertical columns in the table.  It must be an integer. &lt;br /&gt;
  &lt;br /&gt;
The DIM statement for the POWERS matrix which contains five rows and four columns would be as follows:   &lt;br /&gt;
 00040 DIM POWERS(5,4) &lt;br /&gt;
&lt;br /&gt;
===Assigning values to two-dimensional matrix with FOR/NEXT ===&lt;br /&gt;
It can be a little trickier to assign values to a two-dimensional matrix array than it is to an array.  One way to handle it is with a nested FOR/NEXT loop.  The following example uses nested FOR/NEXT loops to assign values to the array POWERS. &lt;br /&gt;
[[image:10.6.jpg]]&lt;br /&gt;
&lt;br /&gt;
Let’s follow the execution sequence of the above example from line 60, where Business Rules! enters the Row loop.  Row equals one at this point.  At the next line, Business Rules! enters the COL loop; COL also equals one at this point.  At line 80, Business Rules! is instructed to READ a data value into the (R,C) position of POWERS.  Since both ROW and COL equal one, the first data table value (1) is assigned to the first row, first column position in the array.&lt;br /&gt;
&lt;br /&gt;
The second time through the COL loop, ROW still equals one but COL equals two. So the READ statement at line 80 assigns the next data item to POWERS(1,2), which is the first row, second column of the POWERS array.  Business Rules! continues to repeat the COL loop until all four columns in the first row are filled.  Since COL is then greater than four, Business Rules! has finished executing the COL loop.  It jumps to the first statement after the loop, where it is instructed to repeat the ROW loop.  ROW will now equal two while the entire COL loop process is again executed four times.  This sequence continues until ROW is greater than five.&lt;br /&gt;
&lt;br /&gt;
===Assigning values to matrices with READ MAT===&lt;br /&gt;
A second, faster way to assign values to both one-dimensional and two-dimensional matrix is by using the MAT keyword in the READ statement.  This method allows you to produce the same results with one statement that it took five lines to do in our last example. &lt;br /&gt;
&lt;br /&gt;
The syntax of a READ statement using MAT is: &lt;br /&gt;
 line# READ MAT array-name &lt;br /&gt;
&lt;br /&gt;
When Business Rules! sees a READ MAT statement, it assigns DATA statement values to the matrix in row-by-row order according to the way the array was dimensioned.  The following set of program lines for example, performs the same operation that our nested FOR/NEXT loops did in the last section:  &lt;br /&gt;
 00040 DIM POWERS(5,4) &lt;br /&gt;
 00050 DATA 1,1E2,1E3,1E4,2,2E2,2E3,2E4,3,3E2,3E3,3E4,4,4E2,4E3,4E4,5,5E2,5E3,5E4 &lt;br /&gt;
 00060 READ MAT POWERS &lt;br /&gt;
&lt;br /&gt;
Enter this into BR and print it to see how it appears on your screen. Is that what you expected?&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 10.4====&lt;br /&gt;
1. Which of the following best describes a two-dimensional matrix? &amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
   a. Two matrix arrays which are printed next to each other. &amp;lt;br&amp;gt;&lt;br /&gt;
   b. A variable containing a list of values that can be referenced by their row and column positions. &amp;lt;br&amp;gt;&lt;br /&gt;
   c. A list of values in a DATA statement. &amp;lt;br&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
2. You wish to refer to the value in the seventh column of the fourth row in the matrix DCHART.  How can you refer to this position so that Business Rules! will understand?&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   a. DCHART(7,4)&amp;lt;br&amp;gt; &lt;br /&gt;
   b. DCHART(4,7) &amp;lt;br&amp;gt;&lt;br /&gt;
   c. DHCART (4),(7) &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. What does the following statement do? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 00090 DIM EIGER(5,8)&lt;br /&gt;
&lt;br /&gt;
   a. Tells Business Rules! that the EIGER array will contain a maximum of 5 rows and 8 columns. &amp;lt;br&amp;gt;&lt;br /&gt;
   b. Tells Business Rules! that EIGER will be an 8x5 array. &amp;lt;br&amp;gt;&lt;br /&gt;
   c. Tells Business Rules! to assign a value of 40 to row 5, column 8 of the EIGER array. &amp;lt;br&amp;gt;&lt;br /&gt;
   d. Tells Business Rules! to reserve space for 5 elements, each with a maximum length of 8 characters, in the EIGER array. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Name two ways to assign values to a two-dimensional matrix: &amp;lt;br&amp;gt;&lt;br /&gt;
   _________________________   and   ________________________. &lt;br /&gt;
&lt;br /&gt;
[[Answers 10.4]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===10.5 Performing arithmetic with two-dimensional matrixes=== &lt;br /&gt;
Imagine that you are a high school math instructor, and you have been working for months to interest three of your brightest -- but least interested -- students in the curriculum.  Finally you decide to hold a competition among them.  The student who averages the highest on the next four test scores will get a prize.  The catch however, is that the prize will only be awarded if all three students average at least 85% on each test. &lt;br /&gt;
&lt;br /&gt;
The students’ test scores can be held in the 3x4 matrix SCORES: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|Roger &lt;br /&gt;
|89 &lt;br /&gt;
|87 &lt;br /&gt;
|94 &lt;br /&gt;
|93&lt;br /&gt;
|- &lt;br /&gt;
|Martha &lt;br /&gt;
|85 &lt;br /&gt;
|90 &lt;br /&gt;
|92 &lt;br /&gt;
|94 &lt;br /&gt;
|-&lt;br /&gt;
|Cheryl &lt;br /&gt;
|81 &lt;br /&gt;
|83 &lt;br /&gt;
|96 &lt;br /&gt;
|100 &lt;br /&gt;
|}  &lt;br /&gt;
In order to find out first whether or not the prize will be given, and second who it will be given to, you need to find the averages of both the column and the row figures in the array.  To try this process out for yourself as you are learning about it in the next few sections, you are going to write a program entitled MOTIVAT.&lt;br /&gt;
&lt;br /&gt;
===Arithmetic with matrix columns===&lt;br /&gt;
Your first objective is to find the average for each test, or column.  To compute the column averages of the SCORES matrix, you will need to dimension a new array variable, SUMCOL.  This array will hold four values: the sums of columns one, two, three and four of the SCORES array.  Go ahead and dimension this array variable now. This is the SCORES array. &lt;br /&gt;
  &lt;br /&gt;
Next, type the following lines into the MOTIVAT program:   &lt;br /&gt;
 00140  FOR C=1 TO 4 &lt;br /&gt;
 00150  FOR R=1 TO 3 &lt;br /&gt;
 00160  LET SUMCOL(C)=SUMCOL(C)+SCORES(R,C) &lt;br /&gt;
 00170  NEXT R &lt;br /&gt;
 00180  PRINT SUMCOL(C)/3 &lt;br /&gt;
 00190  NEXT C &lt;br /&gt;
&lt;br /&gt;
The above code uses nested FOR/NEXT loops to determine the average score for each test.  After Business Rules! has entered both the C and the R loops, the LET statement at line 160 tells it to add the current values of SUMCOL(C) to the value in row R column C of the SCORES array. &lt;br /&gt;
&lt;br /&gt;
Because this is the first time through the C loop, SUMCOL(C) equals SUMCOL(1)  and, because SUMCOL(1) has not yet been assigned a value, its value is currently 0.  Since this is also the first time through the R loop, SCORES(R,C) is equal to the value of SCORES(1,1), which is 89.  Thus the value 0+89 (89) is assigned to the SUMCOL(1) variable. &lt;br /&gt;
&lt;br /&gt;
C remains the same, but R changes to 2 the second time Business Rules! executes the R loop.  This causes the value of SUMCOL(1) to be added to the value at row 2, column 1 of the SCORES array.  Thus SUMCOL(1) is now assigned the value 89+85 (174). &lt;br /&gt;
&lt;br /&gt;
When Business Rules! completes the R loop for the third time, it assigns 174+81 (255) to SUMCOL(1).  It then goes on to execute the PRINT statement at line 180. The printed value is the average of the three test scores for test 1. &lt;br /&gt;
&lt;br /&gt;
Business Rules! then returns to line 140 and executes the C loop three additional times to determine the average scores for tests 2, 3, and 4. &lt;br /&gt;
&lt;br /&gt;
===Arithmetic with matrix rows=== &lt;br /&gt;
Since the overall average on each test was at least 85%, your next objective is to figure out who won the contest.  To do this, you need to average the row totals in the SCORES array. The row arithmetic for this example is similar to the column arithmetic you used in the last section. Before you read ahead, try to write the next lines of the program yourself.&lt;br /&gt;
&lt;br /&gt;
The biggest difference is that the variables in the inner and outer loops are switched.  Also, you will need to dimension another array variable, SUMROW, to the following lines to the MOTOIVAT program: &lt;br /&gt;
&lt;br /&gt;
 00200  FOR R=1 TO 3 &lt;br /&gt;
 00210  FOR C=1 TO 4 &lt;br /&gt;
 00220  LET SUMROW(R)=SUMROW(R)+SCORES(R,C) &lt;br /&gt;
 00230  NEXT C &lt;br /&gt;
 00240  PRINT SUMROW(R)/4 &lt;br /&gt;
 00250  NEXT R &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 10.5====&lt;br /&gt;
1. Who was the winner of the math contest? &amp;lt;br&amp;gt;&lt;br /&gt;
   a. Roger &amp;lt;br&amp;gt;&lt;br /&gt;
   b. Martha &amp;lt;br&amp;gt;&lt;br /&gt;
   c. Cheryl &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Answer:&amp;lt;br&amp;gt;&lt;br /&gt;
1-Run the program to see! &lt;br /&gt;
&lt;br /&gt;
===10.6 More about DIM===&lt;br /&gt;
Business Rules! is flexible in that it does not require you to use DIM statements for (one-dimensional) arrays holding 10 values or less.  You can check this out for yourself by typing the following lines, which assign four values to the TOWEL$ array, into Business Rules!.  Business Rules! will RUN the program without sending an error. (If you wish to print the array, use PRINT MAT TOWEL as a command after you run the program.) &lt;br /&gt;
&lt;br /&gt;
 00010 LET MAT$(1)=”Canon” &lt;br /&gt;
 00020 LET MAT$(2)=”Martex” &lt;br /&gt;
 00030 LET MAT$(3)=”Perry Ellis” &lt;br /&gt;
 00040 LET MAT$(4)=”JC Penney” &lt;br /&gt;
 00050 READ MAT TOWEL$ &lt;br /&gt;
&lt;br /&gt;
When you assign values to an array without first dimensioning it, Business Rules! automatically gives it a size of 10.  In the above example, the TOWEL$ array has room for 10 values--even though only 4 are assigned. &lt;br /&gt;
&lt;br /&gt;
The ability to assign values to arrays without dimensioning them is a very useful timesaver, but this is poor programming style.  Failure to dimension arrays in long and complex programs can make those programs difficult to understand, edit, and debug.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 10.6====&lt;br /&gt;
1. What is the maximum number of values that can be assigned to a two-dimensional array before Business Rules! requires you to dimension the array variable? &amp;lt;br&amp;gt;&lt;br /&gt;
a. 4 &amp;lt;br&amp;gt;&lt;br /&gt;
b. 10 rows, 10 columns (100 values)&amp;lt;br&amp;gt;&lt;br /&gt;
c. 10 &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. True or False: When you assign 6 values to an array without dimensioning it, Business Rules! automatically dimensions the array to six values for you. &lt;br /&gt;
&lt;br /&gt;
[[Answers 10.6]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Chapter Exercise====&lt;br /&gt;
Write a program to assign the 9x9 multiplication table to a two-dimensional matrix and print it out as follows: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|x &lt;br /&gt;
|1 &lt;br /&gt;
|2 &lt;br /&gt;
|3 &lt;br /&gt;
|4 &lt;br /&gt;
|5 &lt;br /&gt;
|6 &lt;br /&gt;
|7 &lt;br /&gt;
|8 &lt;br /&gt;
|9 &lt;br /&gt;
|-&lt;br /&gt;
|1 &lt;br /&gt;
|1 &lt;br /&gt;
|2 &lt;br /&gt;
|3 &lt;br /&gt;
|4 &lt;br /&gt;
|5 &lt;br /&gt;
|6 &lt;br /&gt;
|7 &lt;br /&gt;
|8 &lt;br /&gt;
|9 &lt;br /&gt;
|-&lt;br /&gt;
|2 &lt;br /&gt;
|4 &lt;br /&gt;
|6 &lt;br /&gt;
|8 &lt;br /&gt;
|10 &lt;br /&gt;
|12 &lt;br /&gt;
|14 &lt;br /&gt;
|16 &lt;br /&gt;
|18 &lt;br /&gt;
|-&lt;br /&gt;
|3 &lt;br /&gt;
|3 &lt;br /&gt;
|6 &lt;br /&gt;
|9 &lt;br /&gt;
|12 &lt;br /&gt;
|15 &lt;br /&gt;
|18 &lt;br /&gt;
|21 &lt;br /&gt;
|24 &lt;br /&gt;
|27 &lt;br /&gt;
|-&lt;br /&gt;
|4 &lt;br /&gt;
|4 &lt;br /&gt;
|8 &lt;br /&gt;
|12 &lt;br /&gt;
|16 &lt;br /&gt;
|20 &lt;br /&gt;
|24 &lt;br /&gt;
|28 &lt;br /&gt;
|32 &lt;br /&gt;
|36 &lt;br /&gt;
|-&lt;br /&gt;
|5 &lt;br /&gt;
|5 &lt;br /&gt;
|10 &lt;br /&gt;
|15 &lt;br /&gt;
|20 &lt;br /&gt;
|25 &lt;br /&gt;
|30 &lt;br /&gt;
|35 &lt;br /&gt;
|40 &lt;br /&gt;
|45 &lt;br /&gt;
|-&lt;br /&gt;
|6 &lt;br /&gt;
|6 &lt;br /&gt;
|12 &lt;br /&gt;
|18 &lt;br /&gt;
|24 &lt;br /&gt;
|30 &lt;br /&gt;
|36 &lt;br /&gt;
|42 &lt;br /&gt;
|48 &lt;br /&gt;
|54 &lt;br /&gt;
|-&lt;br /&gt;
|7 &lt;br /&gt;
|7 &lt;br /&gt;
|14 &lt;br /&gt;
|21 &lt;br /&gt;
|28 &lt;br /&gt;
|35 &lt;br /&gt;
|42 &lt;br /&gt;
|49 &lt;br /&gt;
|56 &lt;br /&gt;
|63 &lt;br /&gt;
|-&lt;br /&gt;
|8 &lt;br /&gt;
|8 &lt;br /&gt;
|16 &lt;br /&gt;
|24 &lt;br /&gt;
|32 &lt;br /&gt;
|40 &lt;br /&gt;
|48 &lt;br /&gt;
|56 &lt;br /&gt;
|64 &lt;br /&gt;
|72 &lt;br /&gt;
|-&lt;br /&gt;
|9 &lt;br /&gt;
|9 &lt;br /&gt;
|18 &lt;br /&gt;
|27 &lt;br /&gt;
|36 &lt;br /&gt;
|45 &lt;br /&gt;
|54 &lt;br /&gt;
|63 &lt;br /&gt;
|72 &lt;br /&gt;
|81&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Solutions#CHAPTER 10|Solution]]&lt;br /&gt;
&lt;br /&gt;
NEXT:[[Chapter 11|Full Screen Processing, Using Print Fields and Input Fields]]&lt;br /&gt;
&lt;br /&gt;
[[BR Tutorial|Back to Index]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Tutorial 1]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_7&amp;diff=10844</id>
		<title>Chapter 7</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_7&amp;diff=10844"/>
		<updated>2017-03-08T17:53:14Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Quick Quiz 7.5 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;PRINT is a multi-talented statement.  In this chapter you will use it to clear the screen, to tone the print “bell,” and to produce both unformatted and formatted output.  When you are finished you should be able to: &lt;br /&gt;
  &lt;br /&gt;
* Explain the difference between unformatted and formatted printing. &lt;br /&gt;
* Describe the screen in terms of rows and columns. &lt;br /&gt;
* Use both commas (for zone printing) and semi-colons in a PRINT statement. &lt;br /&gt;
* Describe and use the BELL, NEWPAGE, and TAB options of the print statement. &lt;br /&gt;
* Produce formatted output with PRINT USING and the FORM statement. &lt;br /&gt;
* Explain the uses of the C and N conversion specifications. &lt;br /&gt;
* Explain the uses of the PIC conversion specification, insertion characters &amp;amp; identifiers. &lt;br /&gt;
* Describe and use the POS, X, and SKIP cursor position specifications. &lt;br /&gt;
&lt;br /&gt;
===7.1 The design of your screen===&lt;br /&gt;
Your Business Rules! screen is divided into rows and columns.  A row is the horizontal space that one line of text takes up on the screen.  A column is the vertical space that a single character in each row takes from the top to the bottom of the screen. Business Rules! default screen allows you to see 24 horizontal rows and 80 vertical columns at a time. This default can be changed with the OPEN statement, which you&#039;ll learn about in a later section.  &lt;br /&gt;
&lt;br /&gt;
[[image:7.1.png]]&lt;br /&gt;
&lt;br /&gt;
The information in the right corner of your status line allows you to keep track of the cursor’s current screen position.  The number on the left side of the colon shows the cursor’s row number (since the cursor does not scroll, this number will almost always be 24 when you are writing a program), and the number to the right of the colon shows the column number. &lt;br /&gt;
&lt;br /&gt;
You have already used the PRINT statement for unformatted printing.  When an unformatted PRINT statement is executed, numeric strings which contain more than six whole number digits are printed in exponential form, and numeric strings which contain more than six decimal digits are rounded.  &lt;br /&gt;
&lt;br /&gt;
To demonstrate this, what happens when you run this one-line program? &lt;br /&gt;
&lt;br /&gt;
 00010 PRINT 123456789,.123456789 &lt;br /&gt;
 RUN &lt;br /&gt;
&lt;br /&gt;
The first number (1.2345678e+008) is printed in exponential form, and the second (0.123456) is rounded to six digits. &lt;br /&gt;
&lt;br /&gt;
Formatted PRINT statements allow you to choose the number of digits which will appear before exponentiation or rounding occurs.  Formatted printing is usually used in reports, where information must fit into predetermined slots. This is described later in the chapter. &lt;br /&gt;
&lt;br /&gt;
There is also another kind of printing, accomplished with PRINT FIELDS statements, which allows you to choose both the row and the column that printing will occur in.  PRINT FIELDS will be discussed in another chapter. &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.1==== &lt;br /&gt;
&lt;br /&gt;
1. Match the following: &amp;lt;br&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|A. Formatted ||1) Exponentiation &amp;amp; rounding occurs after 6 digits &lt;br /&gt;
|-&lt;br /&gt;
|B. Rows ||2) Total of 24 &lt;br /&gt;
|-&lt;br /&gt;
|C. Unformatted ||3) Total of 80 &lt;br /&gt;
|-&lt;br /&gt;
|D. Columns || 4) Used mainly in reports &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2. What part of the status line tells you the current column position of the cursor? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   The number just before the colon in the right corner of the status line. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   The number in the center of the status line &amp;lt;br&amp;gt;&lt;br /&gt;
c)   The number just after the colon in the right corner of the status line. &lt;br /&gt;
&lt;br /&gt;
3. Which type(s) of printing allow you to choose the number of digits which will be printed before exponentiation or rounding occurs? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   Unformatted&amp;lt;br&amp;gt;&lt;br /&gt;
b)   Formatted &lt;br /&gt;
&lt;br /&gt;
[[Answers 7.1]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===7.2 Sending PRINT output to the printer===&lt;br /&gt;
&lt;br /&gt;
So far you have only used PRINT to print information on the screen, but this statement can also be used to send information to another file or to a printer (you will learn more about printing to a file when you study the OPEN statement).&lt;br /&gt;
&lt;br /&gt;
To send information to the printer, you must tell Business Rules to use the printer by specifying the Business Rules reserved file number for the printer, which is #255, in your PRINT statement. The example below will send the specified phrase to the printer rather than to the screen: &lt;br /&gt;
&lt;br /&gt;
 10 PRINT #255: &amp;quot;The peddler wore rabbit skin boots.&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Before printing to the printer, you must first open the printer using the OPEN statement. You can also use this statement to specify which printer to print to, or to use a number other than #255 for the printer. For more information on printing, see the Business Rules Wiki at [http://brwiki.brulescorp.com].  The following code will send the print job to the default printer, showing a nice preview window where the user can select any other printer they want before the job is printed.  &lt;br /&gt;
 &lt;br /&gt;
 5 OPEN #255: &amp;quot;name=preview:/, recl=500&amp;quot;,display,output &lt;br /&gt;
&lt;br /&gt;
Business Rules! also has a special file number (#0) for sending information to the screen. File 0 is the Business Rules output window.  &lt;br /&gt;
Since Business Rules! automatically prints to the screen unless it is told to do otherwise, it is not usually necessary to use this code (although you may if you wish).  The following two statements perform the same action: &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT “The acid odor burned her throat.” &lt;br /&gt;
 01000 PRINT #0:”The acid odor burned her throat.” &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.2 ====&lt;br /&gt;
&lt;br /&gt;
1. Where does Business Rules! send PRINT information when a location is not specified in the PRINT statement? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   To the printer. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   To the screen. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   PRINT statements are not executed unless the output location is specified. &lt;br /&gt;
&lt;br /&gt;
2. Which of the following PRINT statements will send the specified string to the printer? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   PRINT 255: AGATE &amp;lt;br&amp;gt;&lt;br /&gt;
b)   PRINT 0 CONCRETE &amp;lt;br&amp;gt;&lt;br /&gt;
c)   PRINT #255: JELLO &lt;br /&gt;
&lt;br /&gt;
[[Answers 7.2]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===7.3 PRINT’s BELL and NEWPAGE options=== &lt;br /&gt;
&lt;br /&gt;
The PRINT statement has two options which cause actions other than printing.  PRINT with the BELL option sends a message to the hardware that causes it to beep, and PRINT with the NEWPAGE option causes the current screen to clear. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PRINT BELL&#039;&#039;&#039; can be useful for error-handling routines or in any situation where you want the operator to pay special attention to what’s going on. &lt;br /&gt;
&lt;br /&gt;
Line 2310 in the following example shows the use of PRINT with the BELL option during an error-handling routine.  The BELL keyword should always be followed with a semi-colon, as shown: &lt;br /&gt;
[[image:7.2.png]]&lt;br /&gt;
&lt;br /&gt;
The above program branches to line 2300 (a remark statement) when the operator causes an error at line 200.  The next line causes the system bell to sound.  It is followed with a printed message to the operator, and then the program branches back to the statement where the error occurred. &lt;br /&gt;
&lt;br /&gt;
When a printer and the BELL option are specified in a PRINT statement (see the example), Business Rules! causes the printer to beep: &lt;br /&gt;
&lt;br /&gt;
 60000 PRINT #255: BELL; &lt;br /&gt;
&lt;br /&gt;
PRINT BELL can also be used as a command in Business Rules!, although its use is mostly limited to discovering what the “bell” in your computer or printer sounds like. &lt;br /&gt;
&lt;br /&gt;
;PRINT NEWPAGE &lt;br /&gt;
The second nonprint option of PRINT erases the screen.  PRINT NEWPAGE can be used at the beginning of a program or anywhere else that you wish to provide a clean screen. &lt;br /&gt;
  &lt;br /&gt;
It is a good practice to include PRINT NEWPAGE as the first executable statement in all of your major programs.  The following example illustrates this usage.  The NEWPAGE keyword should always be followed with a semi-colon, as shown: &lt;br /&gt;
&lt;br /&gt;
[[image:7.3.png]]&lt;br /&gt;
&lt;br /&gt;
When a printer and the NEWPAGE option are specified in a PRINT statement (see the example), Business Rules! causes the printer to advance to the next page: &lt;br /&gt;
&lt;br /&gt;
 60000 PRINT #255: NEWPAGE; &lt;br /&gt;
&lt;br /&gt;
The NEWPAGE option can also be used as a command in Business Rules!.  If you are familiar with other dialects of BASIC, then you should be very careful to remember the difference between NEWPAGE as a command and CLEAR.  NEWPAGE erases the screen without affecting memory.  CLEAR removes all programs and data from Business Rules! current memory, but it does not clean the screen. &lt;br /&gt;
&lt;br /&gt;
Once you have executed a CLEAR command, there is no way to recover the program stored in current memory.  It is a good idea to frequently SAVE and REPLACE programs that you are working on for a number of reasons (such as potential hardware or power failure), but this is twice as important if you are likely to confuse the uses of CLEAR and PRINT NEWPAGE.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.3====&lt;br /&gt;
&lt;br /&gt;
1. When should you use the BELL option of the PRINT command? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   It should be the first executable statement of the program. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   Any situation where the operator should pay special attention to what’s going on. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   Whenever the system clock says it’s twelve o’clock noon. &lt;br /&gt;
&lt;br /&gt;
2. What happens when the NEWPAGE option of the PRINT command is sent to the printer? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   The printer advances the paper to the next page. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   The screen goes blank. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   The printer prints the word “NEWPAGE.” &amp;lt;br&amp;gt;&lt;br /&gt;
d)   Both a and b. &lt;br /&gt;
&lt;br /&gt;
3. What punctuation should always follow the BELL and NEWPAGE keywords when they are used in PRINT statements? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   A colon. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   A comma. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   A semi-colon. &lt;br /&gt;
&lt;br /&gt;
[[Answers 7.3]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===7.4 Unformatted PRINT statements===&lt;br /&gt;
&lt;br /&gt;
All the PRINT statements that you have used so far with this tutorial have been unformatted.  The typical unformatted PRINT statement contains a line number, the PRINT keyword, and one or more data items, which can be either numeric or character expressions.  In the following example, the variable ID_NUMBER$ is the specified data item: &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT ID_NUMBER$ &lt;br /&gt;
&lt;br /&gt;
Unformatted PRINT statements which include more than one data item may use either commas or semi-colons as separators.  When a comma is used, zoned printing occurs. &lt;br /&gt;
&lt;br /&gt;
===Zoned Printing=== &lt;br /&gt;
&lt;br /&gt;
Business Rules! divides output space into five zones of 24 characters each.  On a 132-character-per-line printer, these zones occur at columns 1, 24, 48, 72, and 96. Since the typical screen is only 80 columns wide, zoned printing occurs only in three columns when you are looking at the screen: 1, 24, and 48. (Data items in the fourth and fifth zones are automatically printed only the next line.) &lt;br /&gt;
&lt;br /&gt;
The first data item in a PRINT statement is printed in the first zone.  The second data item is printed in the next available zone (individual data items may take up as many zones as is necessary).  Each data item is printed in turn.  There is no limit to the number of data items which may be used in a single PRINT statement. &lt;br /&gt;
&lt;br /&gt;
If all the zones in a row are used before all the data items in the statement are printed, Business Rules! continues printing in the next row.  The following statement: &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT ID_NUMBER$, NICKNAME$, HEIGHT$, WEIGHT$ &lt;br /&gt;
&lt;br /&gt;
could produce this output on the screen: &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|Column 1 ||Column 24 ||Column 48 &lt;br /&gt;
|-&lt;br /&gt;
|999-64-5607 ||WIZARD ||6/0 &lt;br /&gt;
|-&lt;br /&gt;
|192&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The same statement, when sent to a printer which prints 132 characters per line, would print the information in a single line as follows: &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|Column 1 ||Column 24 ||Column 48 ||Column 72 &lt;br /&gt;
|-&lt;br /&gt;
|999-64-5607      WIZARD          6/0              192 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Overriding zoned printing &lt;br /&gt;
The use of semi-colons instead of commas to separate data items overrides zone printing.  Multiple data items are then printed in one long string, as shown in the following example: &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT ID_NUMBER; NICKNAME$; HEIGHT$; WEIGHT$ &lt;br /&gt;
&lt;br /&gt;
will print this: &lt;br /&gt;
&lt;br /&gt;
999-64-5607WIZARD6/092      &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.4====&lt;br /&gt;
&lt;br /&gt;
1.Business Rules! distinguishes between the use of commas and semi-colons in PRINT statements.  What function do these punctuation symbols perform? &amp;lt;br&amp;gt; &lt;br /&gt;
a)   Operate as data items. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   Determine where PRINT data will be printed (comma=screen, semi-colon=printer). &amp;lt;br&amp;gt;&lt;br /&gt;
c)   Separate data items. &lt;br /&gt;
&lt;br /&gt;
2. What is the maximum number of characters that a single data item may consist of? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   Two zones (48 characters). &amp;lt;br&amp;gt;&lt;br /&gt;
b)   30 &amp;lt;br&amp;gt;&lt;br /&gt;
c)   There is no limit to the number of data items which may be used in a single PRINT statement. &lt;br /&gt;
&lt;br /&gt;
3. What is zoned printing? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   A type of formatted printing. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   Printing from a program that was written in a different time zone. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   Printing of separate data items in preset spaces. &lt;br /&gt;
&lt;br /&gt;
4. Which of the following statements about zoned printing is true? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   Use of semi-colons instead of commas (as data item separators) will override zoned printing. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   When PRINT statement output is directed to the screen, the statement may contain only three data items. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   When a data item takes up more than one zone, the next data item is printed in the next available column. &lt;br /&gt;
&lt;br /&gt;
[[Answers 7.4]] &amp;lt;br&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
====Mid-Chapter Practice:====&lt;br /&gt;
Using your program NEWSAL (from Chapter 6), override zoned printing to list the salary increases for each employee. What else do you think could be done to make the numbers clearer? (Consider spacing and how dollar amounts are usually written).&lt;br /&gt;
&lt;br /&gt;
[[Solutions#CHAPTER 7|Solution]]&lt;br /&gt;
&lt;br /&gt;
===7.5 Leading and trailing spaces===&lt;br /&gt;
&lt;br /&gt;
Whenever Business Rules! prints numeric data items, it adds a leading space (before) and a trailing space (after) the variable.  You should consider these spaces to be part of the printed information.  As an example, study the following statement and its output: &lt;br /&gt;
&lt;br /&gt;
 00010 PRINT TODAYS;WORKER_NUM;COST &lt;br /&gt;
 RUN&lt;br /&gt;
 12  6  2160  &lt;br /&gt;
&lt;br /&gt;
The spaces before each variable is a leading space while the space following each variable is a trailing space. &lt;br /&gt;
&lt;br /&gt;
Business Rules! also adds leading and trailing spaces to data items which are zone printed: &lt;br /&gt;
&lt;br /&gt;
 00010 PRINT TODAYS, WORKER_NUM,COST &lt;br /&gt;
 RUN &lt;br /&gt;
 12                     6                     2160       &lt;br /&gt;
&lt;br /&gt;
Columns 1, 24 and 72 (the column before each variable) are leading spaces.   &lt;br /&gt;
&lt;br /&gt;
But Business Rules! does not add leading and trailing spaces to character data items.  If you are not careful to plan for this, you could end up with output strings that “run” together, as in the following example: &lt;br /&gt;
 [[image:7.4.jpg]]&lt;br /&gt;
  &lt;br /&gt;
The way to correct the problem is to add desired spaces within delimiters when you specify the values of string variables.  The above example could be corrected by adding a space at the beginning and end of the PRINT statement’s “is located in” string: &lt;br /&gt;
&lt;br /&gt;
 00030 PRINT CUST$;” is located in “;LOCATION$ &lt;br /&gt;
 RUN &lt;br /&gt;
&lt;br /&gt;
H.E. Construction is located in Deerfield, IL. &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.5 ====&lt;br /&gt;
&lt;br /&gt;
Study the following set of statements and then answer the questions: &lt;br /&gt;
 00010 LET NUMBER=1121 &lt;br /&gt;
 00020 LET MAGNAME$=”Cycle Digest” &lt;br /&gt;
 00030 LET CIRC=74030 &lt;br /&gt;
 00040 LET SUBSCRIP=52476 &lt;br /&gt;
 00050 PRINT NUMBER;MAGNAME$;CIRC;SUBSCRIP &lt;br /&gt;
&lt;br /&gt;
1. What screen column will the first digit of the NUMBER value be printed in?&amp;lt;br&amp;gt; &lt;br /&gt;
a)   Column 1. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   Column 2. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   Column 3. &lt;br /&gt;
&lt;br /&gt;
2. What screen column will the first letter of the MAGNAME$ variable appear in? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   Column 6. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   Column 7. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   Column 24. &amp;lt;br&amp;gt;&lt;br /&gt;
d)   Column 25. &lt;br /&gt;
&lt;br /&gt;
3. How many blank spaces will there be between the MAGNAME$ and the CIRC values?&amp;lt;br&amp;gt;&lt;br /&gt;
a)   Zero. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   One &amp;lt;br&amp;gt;&lt;br /&gt;
c)   Two &amp;lt;br&amp;gt;&lt;br /&gt;
d)   Thirteen. &lt;br /&gt;
&lt;br /&gt;
[[Answers 7.5]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===7.6 Print&#039;s TAB option===&lt;br /&gt;
Sometimes you will find that your unformatted printing requires greater flexibility than zone printing can give you.  You may want to use more than five zones in a single row, for instance.  This is when the PRINT statement’s TAB option will come in handy. &lt;br /&gt;
  &lt;br /&gt;
;TAB(x) allows you to specify which column the next data item should be printed at (x is the column number).  &lt;br /&gt;
&lt;br /&gt;
Study the following example: &lt;br /&gt;
 00010 PRINT WINDOWS;TAB(20);DOORS;TAB(40);STEPS &lt;br /&gt;
 RUN &lt;br /&gt;
 Column 1        Column 30    Column 50     &lt;br /&gt;
         &lt;br /&gt;
 16                     6                      2160 &lt;br /&gt;
&lt;br /&gt;
Notice that TAB is set off from the data items with semi-colons.  The use of commas would confuse Business Rules! into trying to zone print.  Also notice that the secondary keyword, TAB, is followed by a set of parentheses and the number of spaces until the next data item.  Any numeric expression can be used within these parentheses: whatever number it evaluates to is the column number at which Business Rules! will print the next data item.  Exceptions to this rule are listed below: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|Exception||Result&lt;br /&gt;
|- &lt;br /&gt;
|Current column position of the cursor is greater than x. ||The data item is printed in the next row in column x. &lt;br /&gt;
|-&lt;br /&gt;
|x is negative ||TAB(1) is assumed. &lt;br /&gt;
|-&lt;br /&gt;
|x is not an integer ||X is roudned to the nearest integer. &lt;br /&gt;
|-&lt;br /&gt;
|x is greater than the record length (the number of columns in the row). ||The data item is printed on the next row in column 1. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Business Rules! allows you to use a combination of commas, semi-colons and the TAB option in the same PRINT statement.  Just be sure to remember that TAB should be set off with semi-colons rather than commas. &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.6====&lt;br /&gt;
&lt;br /&gt;
1. What does the x in TAB(x) stand for? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   The number of spaces between columns. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   The column number of the next data item. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   The number of data items to be printed in the next print zone. &lt;br /&gt;
&lt;br /&gt;
2. What happens when the value of x is smaller than the current column position of the cursor? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   The data item is printed in column 1 of the next row. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   The data item is printed in column x of the next row. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   The cursor moves x spaces and prints the data item. &amp;lt;br&amp;gt;&lt;br /&gt;
d)   The data item is printed in the next zone. &lt;br /&gt;
&lt;br /&gt;
3. Write a PRINT statement that achieves the following: &amp;lt;br&amp;gt;&lt;br /&gt;
a)   The value of CHART (108) is printed starting in column 12. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   The value of PEAK (2) is printed in zone 2. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   The statement “this is a new page” is printed in zone 3. &lt;br /&gt;
&lt;br /&gt;
[[Answers 7.6]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Mid-Chapter Practice:====&lt;br /&gt;
Using your program NEWSAL again, use TAB to spread out each salary amount across the screen.&lt;br /&gt;
&lt;br /&gt;
[[Solutions#CHAPTER 7|Solution]]&lt;br /&gt;
&lt;br /&gt;
===7.7 Formatted Printing=== &lt;br /&gt;
When PRINT is used in conjunction with a USING option and the FORM statement, formatted printing is the result.  Formatted printing can be used to regulate the lengths of printed values and to insert characters -- such as dollar signs -- immediately before printed numbers.  It is most often used in the printing of reports. &lt;br /&gt;
&lt;br /&gt;
Formatted printing is separate from unformatted printing; the two types cannot be specified in the same PRINT statement.  The formatted PRINT statement typically includes a line number, the keyword PRINT, the secondary keyword USING along with a line reference to a FORM statement and a required colon, and one or more data items: &lt;br /&gt;
&lt;br /&gt;
 00010 PRINT USING 20: VITAMIN_A,RIBOFLAVIN,CALCIUM,PROTEIN &lt;br /&gt;
&lt;br /&gt;
The above statement tells Business Rules! to print the specified data items using the FORM statement located at line 20.  The format statements are executed only when a PRINT USING statement specifically refers to them.  Otherwise they are ignored.  &lt;br /&gt;
  &lt;br /&gt;
Before we discuss the FORM statement itself, it is important for you to understand some of the FORM statement’s terminology. &lt;br /&gt;
  &lt;br /&gt;
A field, in computer lingo basically refers to the space allotted to a piece of information, usually text. &lt;br /&gt;
  &lt;br /&gt;
When printed, the values of the variables in the following PRINT statement will each occupy their own field.  The length of the value (the number of characters) is not necessarily the same length as the field however--and this is an important distinction.  A field of predetermined length can be reserved for a particular value, but that value does not have to fill the field. &lt;br /&gt;
  &lt;br /&gt;
As an example of this concept, the FORM statement in line 60 below sets up four fields of 15 columns in length (do not be concerned if you do not follow the PRINT USING and FORM statements yet - we are mostly concerned with the printed output in this example).  In each case however, the values within the field are less than fifteen columns wide: &lt;br /&gt;
&lt;br /&gt;
[[image:7.5.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Field #1               Field #2               Field #3              Field #4 &lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.7====&lt;br /&gt;
&lt;br /&gt;
1. Which option of the PRINT statement must be used for formatted printing? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   TAB &amp;lt;br&amp;gt;&lt;br /&gt;
b)   USING &amp;lt;br&amp;gt;&lt;br /&gt;
c)   FORM &lt;br /&gt;
&lt;br /&gt;
2. What punctuation is required after the line-ref in the PRINT USING statement?&amp;lt;br&amp;gt; &lt;br /&gt;
a)   A comma. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   A set of quotation marks. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   A colon. &lt;br /&gt;
&lt;br /&gt;
3. Identify the false statement: &amp;lt;br&amp;gt;&lt;br /&gt;
a)   A field is the amount of horizontal space which is allotted to a piece of information. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   The specifications for formatted and unformatted printing are very similar; they can even be mixed in the same PRINT statement. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   The PRINT USING statement contains a line-ref to the FORM statement that specifies the format of the information to be printed. &lt;br /&gt;
&lt;br /&gt;
[[Answers]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
===7.8 The FORM statement===&lt;br /&gt;
The FORM statement consists of a list of format specifications. A specification is a letter or group of letters followed by a number and separated by commas when listed in a FORM statement. &lt;br /&gt;
&lt;br /&gt;
The FORM statement must contain a line number and the FORM keyword, followed by the Cursor Position Specifications (POS) and the Print Specifications. POS gives Business Rules! details on where the cursor should appear, while the print specification gives Business Rules! details on how to execute the print. Do not be concerned if the following FORM statement illustration looks confusing.  You will have a much clearer understanding of FORM’s syntax when you are finished with this chapter.&lt;br /&gt;
&lt;br /&gt;
 00010 FORM POS 2,N 2,X 10,N 2,X 10,N 2 &lt;br /&gt;
&lt;br /&gt;
Since conversion specifications can be used by themselves, the rest of this lesson and the next lesson will focus mainly on the N, C, and PIC conversion specifications.  The following lesson will then explain three ways to alter the cursor position with the FORM statement. &lt;br /&gt;
&lt;br /&gt;
C and N conversion specifications &lt;br /&gt;
&lt;br /&gt;
The FORM statement provides you with several conversion specification options, but the two that you will probably use most frequently are C and N.  C stands for character, and it signals that the system is to print a character string.  N stands for numeric, and it signals that the system is to print a numeric number.  The second numeric parameter in the specification indicates the length of the field where it will print. &lt;br /&gt;
&lt;br /&gt;
[[image:7.6.png]]&lt;br /&gt;
&lt;br /&gt;
In the above example, line 10 tells Business Rules! to print the specified character strings using the format specifications at line 20.  Line 20 then specifies the printing of two character strings: the first is to be placed in a field of 10 columns.  Notice that character strings are left-aligned. &lt;br /&gt;
The printing of numeric values works much the same way, except they are right-aligned: &lt;br /&gt;
&lt;br /&gt;
[[image:7.7.png]] &lt;br /&gt;
&lt;br /&gt;
When a number is to be printed with a decimal point and one or more decimal digits, this information must be included along with the field length.  The specification is the same as above except that the field length number includes a period and the quantity of decimal digits to be printed. &lt;br /&gt;
&lt;br /&gt;
[[image:7.8.png]]&lt;br /&gt;
&lt;br /&gt;
The above FORM statement indicates that a field length of seven columns should be used (the field length must be long enough room to include both the decimal point and the decimal digits), and that the number to be printed should have two decimal places.  The actual number is then rounded to the number of decimal places specified: &lt;br /&gt;
&lt;br /&gt;
The N and C specifications can be used in the same statement: &lt;br /&gt;
&lt;br /&gt;
[[image:7.9.png]]&lt;br /&gt;
&lt;br /&gt;
You may also specify the printing of literal directly from within the FORM statement.  Also, a single FORM statement may be referenced by more than one PRINT USING statement.  The following example, which uses the same FORM statement to print three different lines, shows how PRINT USING and FORM can be used to print large amounts of data that is to appear in the same format: &lt;br /&gt;
[[image:7.9a.png]]&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.8====&lt;br /&gt;
1. FORM statement specifications can accomplish one of two functions.  Identify the two functions from the following four choices: &amp;lt;br&amp;gt;&lt;br /&gt;
a) Print numeric strings. &amp;lt;br&amp;gt;&lt;br /&gt;
b) Change the cursor position. &amp;lt;br&amp;gt;&lt;br /&gt;
c) Print character strings. &amp;lt;br&amp;gt;&lt;br /&gt;
d) Indicate that a particular type of data item (either string or numeric) is to be printed at the current cursor position. &lt;br /&gt;
&lt;br /&gt;
2. Which two of the following statements is true about the field length specification? &amp;lt;br&amp;gt;&lt;br /&gt;
a) Indicates the amount of space to be allotted to a character or numeric string. &amp;lt;br&amp;gt;&lt;br /&gt;
b) Cannot indicate a field length of greater than 15 columns.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Directly follows the C and N conversion specifications. &lt;br /&gt;
&lt;br /&gt;
3. What does Business Rules! do with extra spaces in a field containing a numeric value? &amp;lt;br&amp;gt;&lt;br /&gt;
a) Inserts one space before and one space after the value. &amp;lt;br&amp;gt;&lt;br /&gt;
b) Puts all the spaces to the left of the variable. &amp;lt;br&amp;gt;&lt;br /&gt;
c) Ignores extra spaces. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. Which of the following FORM statements would print the number 890.546 just as it appears here? &amp;lt;br&amp;gt;&lt;br /&gt;
a)            00010 FORM N 3.3 &amp;lt;br&amp;gt;&lt;br /&gt;
b)            00020 FORM N 6.3 &amp;lt;br&amp;gt;&lt;br /&gt;
c)            00030 FORM n 7.3  &lt;br /&gt;
 &lt;br /&gt;
5. True or False: When PRINT with the USING option and the FORM statement are used together, all information to be printed must be included in the PRINT USING statement. &amp;lt;br&amp;gt;&lt;br /&gt;
[[Answers 7.8]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Mid-Chapter Practice:====&lt;br /&gt;
Once again, use NEWSAL and create a FORM statement to print the new salaries in different positions on the screen.&lt;br /&gt;
&lt;br /&gt;
===7.9 PIC Conversion specification===&lt;br /&gt;
One other conversion specification that we will discuss is PIC.  PIC allows you to insert symbols such as dollar signs, commas or decimal places into a number by telling Business Rules! to print the data item according to the picture specified in parentheses. &lt;br /&gt;
&lt;br /&gt;
In the following example, the PIC specification tells Business Rules! to change the number in the PRINT USING statement to a dollar amount.  &lt;br /&gt;
&lt;br /&gt;
[[image:7.9b.png]]&lt;br /&gt;
&lt;br /&gt;
The dollar signs are special characters that operate both as insertion characters and as digit identifiers.  As insertion characters, they tell the system to insert one dollar sign just before the first digit in the number. As digit identifiers, they tell the system to put a digit from the number to be printed in their places.  If there are more digit identifiers than there are digits (as in the following case, where there are six dollar signs and only four digits), Business Rules! prints a space instead of the extras. &lt;br /&gt;
&lt;br /&gt;
The comma and the period which appear within the parentheses are insertion characters.  Most characters on your keyboard (except Z, #, B, CR, DR, and DB) can be used as insertion characters, but these are two of the most common.  (Other common characters include the - and + symbols.)  The pound signs (##) appearing after the period are more digit identifiers.  Number signs tell the system to print a digit at that spot even if it must be a zero.  &lt;br /&gt;
&lt;br /&gt;
One other symbol, the asterisk, can also be used as both a digit identifier and an insertion character.  It is most often used when printing amounts on checks.  It differs from the dollar sign in that all the symbols are either printed or replaced with stars; none are replaced with spaces.  (The asterisk should only be used in positions to the left of the decimal point.) &lt;br /&gt;
&lt;br /&gt;
[[image:7.9c.png]]&lt;br /&gt;
&lt;br /&gt;
The PIC conversion specification allows you to use all of the symbols in the following chart.  Many of these are not discussed in the above section, but a brief description is included here for your reference.&lt;br /&gt;
&lt;br /&gt;
===Symbols and Functions===&lt;br /&gt;
&lt;br /&gt;
$ - Inserts a dollar sign.  When more than one is used, indicates that digits from the number to be printed are to take their place.  Extra symbols (those not replaced with a number or printed as a dollar sign) are replaced with spaces when formatted. &amp;lt;br&amp;gt;&lt;br /&gt;
, Inserts a comma where specified. &amp;lt;br&amp;gt;&lt;br /&gt;
. Inserts a decimal point where specified.  Indicates that all digits to the right of this position are decimal characters. &amp;lt;br&amp;gt;&lt;br /&gt;
- Inserts a minus sign where specified.  Also serves as a digit identifier when used in multiples. Extra symbols are replaced with spaces when formatted. &amp;lt;br&amp;gt;&lt;br /&gt;
+ Inserts a plus sign where specified.  Also serves as a digit identifier when used in multiples. Extra symbols are replaced with spaces when formatted. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt; Inserts an asterisk sign where specified.  Also serves as a digit identifier when used in multiples. Extra symbols are printed (not replaced with spaces) when formatted. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; Digit identifier.  Indicates that a digit is to be printed at that spot even if the digit is zero. (Recommended for most decimal place usages.) &amp;lt;br&amp;gt;&lt;br /&gt;
B Inserts a blank space where specified. &amp;lt;br&amp;gt;&lt;br /&gt;
CR Credit insertion character.  Printed only when the number is negative.&amp;lt;br&amp;gt;&lt;br /&gt;
DR Debit insertion character.  Printed only when the number is negative. &amp;lt;br&amp;gt;	&lt;br /&gt;
DB Debit insertion character.  Printed only when the number is negative. &amp;lt;br&amp;gt;&lt;br /&gt;
Z Digit identifier used for zero suppression. Leading zeros are always suppressed.  Digits and decimal digits (including zero) are printed only when the entire number is nonzero. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.9====&lt;br /&gt;
1. What does the PIC conversion specification do? &amp;lt;br&amp;gt;&lt;br /&gt;
a) Tells Business Rules! to print a number according to the picture specified within parentheses. &amp;lt;br&amp;gt;&lt;br /&gt;
b) Tells Business Rules! to pick three conversion specifications and format them. &amp;lt;br&amp;gt;&lt;br /&gt;
c) Tells Business Rules! to move the cursor to the specified position. &lt;br /&gt;
&lt;br /&gt;
2. What is an insertion character? &amp;lt;br&amp;gt;&lt;br /&gt;
a) A character used in the PIC specification that is later inserted in a formatted number. &amp;lt;br&amp;gt;&lt;br /&gt;
b) The # sign. &amp;lt;br&amp;gt;&lt;br /&gt;
c) A character that is inserted in a program line after the line was already written.&lt;br /&gt;
 &lt;br /&gt;
3. What is a digit identifier? &amp;lt;br&amp;gt;&lt;br /&gt;
a) Either the + or - signs, which are used to signify that a digit is about to be printed. &amp;lt;br&amp;gt;&lt;br /&gt;
b) A special character used with PIC that tells the system it should be replaced with one digit from the number to be printed. &amp;lt;br&amp;gt;&lt;br /&gt;
c) Any of the following digits: 0,1,2,3,4,5,6,7,8, or 9.&lt;br /&gt;
 &lt;br /&gt;
[[Answers 7.9]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Mid-Chapter Practice:====&lt;br /&gt;
&lt;br /&gt;
Finally, use PIC to print the dollar sign and commas appropriately with your salary figures in NEWSAL.&lt;br /&gt;
&lt;br /&gt;
===7.10 Changing cursor position===&lt;br /&gt;
&lt;br /&gt;
The FORM statement’s conversion specifications, described in the above two lessons, allow you to specify the length or a “picture” of the information to be printed.  When Business Rules! encounters a conversion specification, it begins printing the information at whatever spot the cursor currently occupies.  Because of this, fields will always start from the first column and be placed back-to-back unless you change the cursor position with one of three options: POS, X, or SKIP. &lt;br /&gt;
&lt;br /&gt;
;Changing Cursor position with POS &lt;br /&gt;
With the POS option, you can specify the exact column position to which the cursor must go.  The following statement, for instance, changes the cursor position to column 56, and then uses the PIC specification to print a check amount.  Notice that the PRINT USING statement occurs after the FORM statement in this case.  Business Rules! looks at the PRINT USING statement line-ref to determine which FORM statement to use, so the two different statements can appear in any order and at any interval.&lt;br /&gt;
[[image:7.9d.png]]&lt;br /&gt;
&lt;br /&gt;
(The $ symbol begins in Column 56) &lt;br /&gt;
&lt;br /&gt;
;Changing Cursor position with X &lt;br /&gt;
The  X option tells Business Rules! to jump past the number of spaces which is specified just after the X.  The following example prints a data item in column one, then jumps past the 10 columns specified with X 10 and prints a data item in column 24. &lt;br /&gt;
&lt;br /&gt;
[[image:7.9e.png]]&lt;br /&gt;
&lt;br /&gt;
;Changing or Keeping Cursor position with SKIP &lt;br /&gt;
The SKIP option works like pressing ENTER: it moves the cursor down the specified number of rows and back to column one. &lt;br /&gt;
In the following example, a number is printed with PIC, then SKIP 1 returns the cursor to the first position in the next line and another number with a leading minus sign is printed.  A second SKIP again returns the cursor to the next line, where a bar (which serves as an = sign) is printed.  A third SKIP brings the cursor down again; the difference between the first two numbers is then printed and followed by the word TOTAL: &lt;br /&gt;
&lt;br /&gt;
[[image:7.9f.jpg]]&lt;br /&gt;
&lt;br /&gt;
Using cursor position specifications without conversion specifications &lt;br /&gt;
Except in one or two unusual cases, FORM’s cursor position specifications should always be followed with a conversion specification that prints a specific piece of information.  In the example below, a PRINT USING statement specifies that the FORM statement at line 20 should be used to print the specified data.  When Business Rules! goes to line 20 though, it finds that there are more data items than there are conversion specifications.  Zippy the Cursor thinks this is no big deal: he’ll just go back to the beginning of the FORM statement and use the same specifications over until all the data items are printed. &lt;br /&gt;
[[image:7.9g.png]]&lt;br /&gt;
&lt;br /&gt;
Where there is one conversion specification, Zippy uses the same FORM statement multiple times, and gets everything printed. &lt;br /&gt;
&lt;br /&gt;
In this next example, an error occurs. Can you tell what the problem is and how to fix it?&lt;br /&gt;
[[image:7.9h.png]] &lt;br /&gt;
&lt;br /&gt;
(It’s missing an output specification).  To print the months at intervals of 10 spaces, one possible solution is shown below. Notice that when N or C is not followed by a number, any size string can follow it.&lt;br /&gt;
&lt;br /&gt;
[[image:7.9i.jpg]]&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 7.10====&lt;br /&gt;
&lt;br /&gt;
1. Conversion specifications tell Business Rules! to print a data item at which cursor position? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Column 1. &amp;lt;br&amp;gt;&lt;br /&gt;
b) The current cursor position. &amp;lt;br&amp;gt;&lt;br /&gt;
c) The column after the current cursor position. &lt;br /&gt;
&lt;br /&gt;
2. A FORM statement must always be placed immediately after a PRINT USING statement, True or False? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. What does the POS option of the FORM statement do? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Tells Business Rules! to print a data item at the specified column position. &amp;lt;br&amp;gt;&lt;br /&gt;
b) Tells Business Rules! to move the cursor past the specified number of columns. &amp;lt;br&amp;gt;&lt;br /&gt;
c) Tells Business Rules! to move the cursor to the specified column position. &lt;br /&gt;
&lt;br /&gt;
4. What does the X option of the FORM statement do? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Tells Business Rules! to move the cursor past the specified number of columns. &amp;lt;br&amp;gt;&lt;br /&gt;
b) Tells Business Rules! to erase the specified number of characters. &amp;lt;br&amp;gt;&lt;br /&gt;
c) Tells Business Rules! to print a data item at the specified column position. &lt;br /&gt;
&lt;br /&gt;
5. What does the SKIP option of the FORM statement do? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Tells Business Rules! to print the specified data items in bold face. &amp;lt;br&amp;gt;&lt;br /&gt;
b) Tells Business Rules! to move the cursor past the specified number of columns. &amp;lt;br&amp;gt;&lt;br /&gt;
c) Tells Business Rules! to move the cursor back to column one and down the specified number of rows. &lt;br /&gt;
&lt;br /&gt;
6. What happens when the PRINT USING statement specifies more data items than the FORM statement has conversion specifications? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a) Business Rules! enters an infinite loop. &amp;lt;br&amp;gt;&lt;br /&gt;
b) Business Rules! continues executing the FORM statement until all the data items are printed. &amp;lt;br&amp;gt;&lt;br /&gt;
c) Business Rules! prints as many data items as there are conversion specifications, then goes on to the next program line.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
[[Answers 7.10]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Chapter 7 Challenge:====&lt;br /&gt;
Once again, use NEWSAL and put everything from this chapter together to print the salaries as shown below:&lt;br /&gt;
&lt;br /&gt;
[[image:7.9j.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[Solutions#CHAPTER 7|Solution]]&lt;br /&gt;
&lt;br /&gt;
NEXT:[[Chapter 8|FOR/NEXT and ON GOTO]]&lt;br /&gt;
&lt;br /&gt;
[[BR Tutorial|Back to Index]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Tutorial 1]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Answers_7.8&amp;diff=10843</id>
		<title>Answers 7.8</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Answers_7.8&amp;diff=10843"/>
		<updated>2017-03-08T17:44:19Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1-b and d; 2-a and c; 3-b; 4-c; 5-False&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Tutorial Answers]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_8&amp;diff=10842</id>
		<title>Chapter 8</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Chapter_8&amp;diff=10842"/>
		<updated>2017-03-08T17:43:24Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Looping and more branching experience is what you’ll learn in this chapter. When you’re done you should be able to: &amp;lt;br&amp;gt;&lt;br /&gt;
*  Use the FOR and NEXT statements to create a loop. &amp;lt;br&amp;gt;&lt;br /&gt;
*  Utilize the loop variable in expressions.&amp;lt;br&amp;gt;&lt;br /&gt;
*  Understand the execution sequence of nested FOR/NEXT loops.&amp;lt;br&amp;gt;&lt;br /&gt;
*  Describe an array, and understand the difference between a one-dimensional and a two-dimensional array.&amp;lt;br&amp;gt;&lt;br /&gt;
*  Use the ON GOTO statement in a program.&amp;lt;br&amp;gt;&lt;br /&gt;
*  Use the ON GOSUB statement in a program.&amp;lt;br&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
===8.1 FOR / NEXT, ON GOTO, ON GOSUB &amp;amp; RENUM===&lt;br /&gt;
So far you have learned about the type of loop that you can create with GOTO statements, and you have experienced what can happen when a program enters an infinite loop.  Business Rules! also allows you to use two separate statements, FOR and NEXT, to create loops that are executed in a specified number of times.&lt;br /&gt;
&lt;br /&gt;
FOR / NEXT loops always begin with a FOR statement and end with a NEXT statement.  The following section of code shows an example. Type this example into Business Rules! and RUN it:&lt;br /&gt;
&lt;br /&gt;
 00010 FOR X=1 TO 10&lt;br /&gt;
 00020   PRINT X&lt;br /&gt;
 00030 NEXT X&lt;br /&gt;
&lt;br /&gt;
The FOR statement in line 10 specifies the name of the loop variable, X, and beginning and ending values for that variable.  The first time that this loop is executed, X will equal one.  The second time the loop is executed, X will equal two, then three, and so on until its value is greater than 10 (which is the specified ending value).&lt;br /&gt;
&lt;br /&gt;
The NEXT statement at line 30 simply marks the end of the loop.  When Business Rules! reaches the NEXT statement, it returns to the FOR statement and tests the value of X.  If X is less than or equal to the specified ending value (10), then the loop is executed.  If X is greater than 10, program execution jumps to the first statement after the end of the loop.&lt;br /&gt;
&lt;br /&gt;
All the statements between FOR and NEXT are executed as part of the loop.  As in the above case, statements which are contained within a loop are usually tabbed in a few spaces so that it is easy to identify that they belong to the loop.&lt;br /&gt;
&lt;br /&gt;
====Focus on FOR====&lt;br /&gt;
The syntax of the FOR statement is as follows:                              &lt;br /&gt;
&lt;br /&gt;
[[image:for.png|600px]]&lt;br /&gt;
&lt;br /&gt;
The “num-var” is the name of the loop variable; it can be any numeric variable.The “num-expr TO num-expr” portion of the statement identifies the beginning and ending variables (a “num-expr” can be any numeric expression).The “STEP num-expr” portion of the statement is optional.  It tells Business Rules! how much to increment (add to) the loop variable each time the loop is executed; when a STEP amount is not specified, Business Rules! assumes a default value of one.&lt;br /&gt;
&lt;br /&gt;
The following are examples of FOR statements:&lt;br /&gt;
&lt;br /&gt;
 00010 FOR WAX = 3 TO 16&lt;br /&gt;
&lt;br /&gt;
The beginning value of WAX (the loop variable) will be 3; the ending value will be 16.  The loop will be executed a total of 14 times.&lt;br /&gt;
&lt;br /&gt;
 00100 FOR I = N*.5 TO 10&lt;br /&gt;
&lt;br /&gt;
The Numeric expression N*.5 determines the beginning value of I.  If N equals 10, the beginning value will be 5.&lt;br /&gt;
&lt;br /&gt;
 01000 FOR T = 10 TO -10 STEP -1&lt;br /&gt;
&lt;br /&gt;
The beginning value of T is 10; the ending value is -10.  The increment is -1 (if it were +1, the loop would not execute).  The loop will be executed a total of 21 times.&lt;br /&gt;
&lt;br /&gt;
 10000 FOR N = 100 TO 400 STEP 100&lt;br /&gt;
&lt;br /&gt;
The beginning value of N is 100; the ending value is 400.  N will increment by 100 each of the four times the loop is executed.&lt;br /&gt;
&lt;br /&gt;
====Focus on NEXT====&lt;br /&gt;
&lt;br /&gt;
NEXT is one of Business Rules!&#039;s shortest statements. Its syntax is as follows:&lt;br /&gt;
&lt;br /&gt;
[[image:next.png|350px]]&lt;br /&gt;
&lt;br /&gt;
The NEXT statement’s “num-var” must be the same num-var which is specified in the corresponding FOR statement.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|RIGHT||WRONG &lt;br /&gt;
|-&lt;br /&gt;
|00070 FOR P = 1 TO 30 ||  00070 FOR P = 1 TO 30&lt;br /&gt;
|-&lt;br /&gt;
|00080 PRINT P ||  00080 PRINT P&lt;br /&gt;
|-&lt;br /&gt;
|00090 NEXT P ||  00090 NEXT T&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The num-var in 90 must match the num-var in line 70.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 8.1====&lt;br /&gt;
1. How many times will Business Rules! execute a FOR/NEXT loop?&lt;br /&gt;
&lt;br /&gt;
a)   The number of times specified with the STEP option.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   An infinite number of times.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Until the value of the loop variable is greater than the specified ending value.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Which item in the following FOR statement is the loop variable?&lt;br /&gt;
&lt;br /&gt;
 00010 FOR P = I TO X STEP N&lt;br /&gt;
&lt;br /&gt;
a)   P&amp;lt;br&amp;gt;&lt;br /&gt;
b)   I&amp;lt;br&amp;gt;&lt;br /&gt;
c)   X&amp;lt;br&amp;gt;&lt;br /&gt;
d)   N&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. What does the STEP option do?&lt;br /&gt;
&lt;br /&gt;
a)   Determines the amount that the loop variable is to be incremented.&amp;lt;br&amp;gt;&lt;br /&gt;
b)   Specifies the number of times that a loop is to be executed.&amp;lt;br&amp;gt;&lt;br /&gt;
c)   Sets the default value of the loop variable.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Answers 8.1]]&lt;br /&gt;
&lt;br /&gt;
===8.2 Using the FOR / NEXT loop===&lt;br /&gt;
FOR / NEXT loops are useful for a number of applications.  They can be used to repeat execution of a set of program lines N number of times or to cause time delays in your program.  The increment of the loop variable can be used in mathematical operations.  FOR / NEXT loops are also often used with arrays, which we will discuss later in this chapter. &lt;br /&gt;
&lt;br /&gt;
Using FOR/NEXT to repeat execution of a set of program lines. &lt;br /&gt;
Imagine that you are writing a computer game called GUESSWORD.  The object of the game is to guess the program’s secret word. &lt;br /&gt;
&lt;br /&gt;
The program then tells you how many of the letters in the word you guessed are also in the computer’s word.  To make the game both fun and challenging for a wide variety of people, you decide to let the player choose the number of chances he or she gets to guess the correct word. &lt;br /&gt;
&lt;br /&gt;
In order for this program to work properly, you would need to write a routine that compares each letter in the guessed word to each letter in the secret word.  This routine could then be enclosed in a FOR / NEXT loop that is repeated as many times as the player said it should be.  The following example shows the structure of this programming problem: &lt;br /&gt;
  [[image:8.1.png]]&lt;br /&gt;
&lt;br /&gt;
(The word=comparison routine goes where you see the &amp;quot;o&amp;quot;) &lt;br /&gt;
&lt;br /&gt;
====Using LOOPS to create time delays====&lt;br /&gt;
&lt;br /&gt;
The following example waits for an event to occur. The maximum time it will wait is 10 seconds. The event is the creation of a report data file named &amp;quot;report.prn&amp;quot; located in the &amp;quot;prl&amp;quot; folder. &lt;br /&gt;
&lt;br /&gt;
 01010 FOR X = 1 TO 10 &lt;br /&gt;
 01020    SLEEP(1)&lt;br /&gt;
 01030    IF EXISTS(&amp;quot;prl\report.prn&amp;quot;) THEN GOTO PRINT_REPORT&lt;br /&gt;
 01040 NEXT X &lt;br /&gt;
&lt;br /&gt;
When Business Rules! begins executing the above loop, it assigns a value of one to X.  The second time the loop is executed Business Rules! replaces the value of X with a 2. It continues to reassign the value of X, each time the loop is executed, until X is greater than 10. &lt;br /&gt;
&lt;br /&gt;
However, if the file &amp;quot;report.prn&amp;quot; is placed into the &amp;quot;prl&amp;quot; folder before 10 seconds have elapsed, then the program will exit the loop and proceed at the PRINT_REPORT label.&lt;br /&gt;
&lt;br /&gt;
====Using the LOOP variable in mathematical operations====&lt;br /&gt;
&lt;br /&gt;
You have seen how the loop variable in the FOR/NEXT loop can be used to execute a procedure a specific number of times.  This variable does not only serve as the loop’s counting mechanism, however, it can be used in other expressions within the loop as well.&lt;br /&gt;
 &lt;br /&gt;
Let’s look at an example.  Imagine that you have a young cousin who is just learning her multiplication tables.  She comes and asks you to write down the products in the 3x table.  You write them down for her, and a couple days later she comes back and asks for the products in the 4x table.  You can see that this could go on for quite a while, so you decide to write a program that produces the answers for each multiplication table as your cousin needs them. &lt;br /&gt;
&lt;br /&gt;
How will you go about this?  Look at the following section of program code.  It accomplishes the same thing as the two that follow it, but more efficiently.  Line 20 assigns the operator’s choice of the times table to the variable TABLE.  The FOR statement in line 30 then assigns NUMBER to be the loop variable.  Each time the loop is executed, NUMBER will increase by one.  Also each time the loop is executed, line 40 multiplies TABLE and the current value of NUMBER together to come up with the next times table product. &lt;br /&gt;
[[image:8.2.png]]&lt;br /&gt;
 &lt;br /&gt;
[[image:8.3.png]]&lt;br /&gt;
 &lt;br /&gt;
[[image:8.4.png]]&lt;br /&gt;
&lt;br /&gt;
====Nested FOR / NEXT loops====&lt;br /&gt;
&lt;br /&gt;
It is possible to nest FOR/NEXT loops, or put one loop inside another.  It is important to understand the execution sequence of this programming device. &lt;br /&gt;
Study the following set of nested FOR/NEXT loops and see if you can predict their execution sequence.  How many times will the outer loop be executed?  How many times will the inner loop be executed? &lt;br /&gt;
&lt;br /&gt;
 00010 FOR A=1 TO 4 -------------------------------------| &lt;br /&gt;
 00015   PRINT “A”                                   		  outer loop &lt;br /&gt;
 00020   FOR B=1 TO 2 -------------------|  &lt;br /&gt;
 00025     PRINT TAB(5);”B”      	 inner loop  &lt;br /&gt;
 00030   NEXT B ------------------------------|   &lt;br /&gt;
 00040 NEXT A -----------------------------------------------| &lt;br /&gt;
&lt;br /&gt;
Once you have tried to determine the execution sequence, type the example into Business Rules! and RUN it.  You should find that the program prints in two columns.  Each time that Business Rules! begins execution of the outer loop, it prints an “A” in the first column.  And each time that Business Rules! executes the inner loop, it prints a “B” in column six of the screen.  Count the number of times and the order in which Business Rules! executes each group.  Were your guesses about the execution sequence correct? &lt;br /&gt;
&lt;br /&gt;
[[image:8.5.jpg]]&lt;br /&gt;
&lt;br /&gt;
A rule to remember about nested FOR/NEXT loops is that the inner loop is executed its specified number of times each time that the outer loop is executed.  &lt;br /&gt;
&lt;br /&gt;
Keep in mind that a nested FOR/NEXT loop cannot be half in and half out of another loop: it must be contained entirely within another loop.  The following right and wrong examples illustrate this point. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|Right||Wrong &lt;br /&gt;
|-&lt;br /&gt;
|00010 for t=1 to 6 || 00010 for t=1 to 6 &lt;br /&gt;
|-&lt;br /&gt;
|00020 for n=0 to -3 step -1 || 00020 for n=0 to -3 step -1 &lt;br /&gt;
|-&lt;br /&gt;
|00030 next n || 00030 next t &lt;br /&gt;
|-&lt;br /&gt;
|00040 next t || 00040 next n &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===The RENUM Command=== &lt;br /&gt;
The RENUM command is a handy little command with an amazing set of powers.  It not only knows how to renumber an irregular list of line numbers (due to insertions, deletions and such) with perfectly incremented replacements, but it also keeps track of the line references within your code and changes them right along with its renumbering.  As an example, look at the following lines of code (which by the way, contain an infinite loop): &lt;br /&gt;
&lt;br /&gt;
 00005 PRINT “What is your password?” &lt;br /&gt;
 00012 INPUT PASSWORD$ &lt;br /&gt;
 00017 IF PASSWORD$=”WICHITA” OR PASSWORD$=“Wichita” THEN GOTO 30 ELSE GOTO 20 &lt;br /&gt;
 00020 PRINT “Access denied” &lt;br /&gt;
 00025 GOTO 4000 &lt;br /&gt;
 00030 PRINT “Hello, Mark.” &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 04000 END &lt;br /&gt;
&lt;br /&gt;
To renumber this section of code so that the first line is 00010 and each following line increments by 10, you enter: &lt;br /&gt;
RENUM ENTER &lt;br /&gt;
&lt;br /&gt;
This command would change the example to: &lt;br /&gt;
 00010 PRINT “What is your password?” &lt;br /&gt;
 00020 INPUT PASSWORD$ &lt;br /&gt;
 00030 IF PASSWORD$=”WICHITA” OR “Wichita” THEN GOTO 60 &lt;br /&gt;
ELSE GOTO 40 &lt;br /&gt;
 00040 PRINT “Access denied” &lt;br /&gt;
 00050 GOTO 4540 &lt;br /&gt;
 00060 PRINT “Hello, Mark.” &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 04540 END &lt;br /&gt;
&lt;br /&gt;
Notice that the line-ref (30) of the GOTO statement in line 40 is changed right along with the number of the line that it refers to.&lt;br /&gt;
 &lt;br /&gt;
====Practice with nested FOR / NEXT LOOPS====&lt;br /&gt;
The best way to learn about nesting a FOR/NEXT loop is to do it for yourself.  We’ll start with one loop at a time. &lt;br /&gt;
&lt;br /&gt;
Let’s imagine that you are writing a program and you want it to start in a cheerful way.  You decide that one way to do this is to ask the user’s name, then send that person a message of “Hi,” the person’s name, and an exclamation point.  And just for fun, you decide to send the same message ten times so that it scrolls partly up the screen.  Go ahead and write the program code (using a FOR/NEXT loop) that would provide output similar to the following: &lt;br /&gt;
&lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
 Hi Billy! &lt;br /&gt;
&lt;br /&gt;
Now let’s imagine that after running the section of program code you’ve just created, you decide each of the ten “Hi Billy!” lines should appear farther apart.  The way that Business Rules! would accomplish this is to PRINT several blank lines between each “Hi Billy!” line.  The following FOR/NEXT loop, inserted into the middle of your current FOR/NEXT loop, should do just this.  Go ahead and place this loop into your own program; you may need to do some experimenting to determine exactly where it should go.  We provide line numbers in this example, but you may need to change them.&lt;br /&gt;
&lt;br /&gt;
 00030    FOR S=1 TO 15 &lt;br /&gt;
 00040      PRINT &lt;br /&gt;
 00050    NEXT S &lt;br /&gt;
&lt;br /&gt;
When you now RUN this double-loop program, the ten “Hi!” messages should scroll up the left side of the screen at 15-line intervals. &lt;br /&gt;
But wait!  Those messages scroll too fast!  Let’s insert a third FOR/NEXT loop inside the second one to slow the whole process down.  It should look something like the following: &lt;br /&gt;
&lt;br /&gt;
 00043       FOR T=1 TO 500000 &lt;br /&gt;
 00047       NEXT T &lt;br /&gt;
&lt;br /&gt;
This will cause the computer to count to 500,000 every time it prints something, slowing the whole process down so we can watch the messages scroll past. You may have to experiment with different values to get a value that runs at a good speed on your computer. &lt;br /&gt;
  &lt;br /&gt;
Using a FOR/NEXT loop to slow something down is hugEly dependant upon the speed of your computer. A better way to slow your program down is to use the SLEEP command. Erase the last for next loop you added by deleting lines 43 and 47 (or whichever line numbers they have in your code) from your program. To do this, you have to type &amp;quot;DEL 43&amp;quot; and press enter. Then type &amp;quot;DEL 47&amp;quot; and press enter. Now, add a new line that looks like the following: &lt;br /&gt;
&lt;br /&gt;
 00045       SLEEP(.05) &lt;br /&gt;
&lt;br /&gt;
The sleep command will cause your computer to rest for a set period of time. You specify the time to sleep in seconds. This command makes the computer rest for one twentieth of a second between each print statement. &lt;br /&gt;
 &lt;br /&gt;
You can use the RENUM command to renumber your program at any time.&lt;br /&gt;
&lt;br /&gt;
====Quick Quiz 8.2====&lt;br /&gt;
&lt;br /&gt;
1. How many total times will the inner FOR/NEXT loop in the following example be executed? &amp;lt;br&amp;gt;&lt;br /&gt;
 00030 FOR X = 10 TO -10 STEP -4 &lt;br /&gt;
 00040   FOR Y = 1 TO 3 &lt;br /&gt;
 00050   NEXT Y &lt;br /&gt;
 00060 NEXT X &lt;br /&gt;
&lt;br /&gt;
a)   60 times. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   3  times. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   18 times. &amp;lt;br&amp;gt;&lt;br /&gt;
d)   6  times. &lt;br /&gt;
&lt;br /&gt;
2. What does the RENUM command do? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   Changes the number of times a FOR/NEXT loop is executed. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   Renumbers an irregular listing of program lines. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   Goes through an entire program and changes all line references to the specified number. &lt;br /&gt;
&lt;br /&gt;
3. Which of the following is not true about nested FOR/NEXT loops? &amp;lt;br&amp;gt;&lt;br /&gt;
a)   An inner loop must be contained entirely within the next outer loop. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   Business Rules! allows you to next up to 20 loops at a time. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   A nested loop can share a NEXT statement with its outer loop. &lt;br /&gt;
&lt;br /&gt;
[[Answers 8.2]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Mid-Chapter Exercise====&lt;br /&gt;
Create a program that prints a triangle of stars on your screen. It should look something like this:&lt;br /&gt;
&lt;br /&gt;
[[image:8.6.jpg]]&lt;br /&gt;
&lt;br /&gt;
*hint... you will need to use two FOR statements within each other to make it work. Begin by writing a program to print the number of stars that the user requests, then modify it to output lines of stars as seen above.&lt;br /&gt;
&lt;br /&gt;
[[Solutions#CHAPTER 8|Solution]]&lt;br /&gt;
&lt;br /&gt;
===8.3 The ON GOTO statement===&lt;br /&gt;
&lt;br /&gt;
You have already learned how the GOTO and GOSUB statements can be used to unconditionally transfer executions to another line or subroutine of a program.  ON GOTO and ON GOSUB are similar statements that conditionally transfer execution to another line or subroutine.  The Reason these transfers are considered conditional is that they make the transfer based on the value of a numeric expression in the statement. &lt;br /&gt;
&lt;br /&gt;
====The ON GOTO statement====&lt;br /&gt;
 &lt;br /&gt;
Let’s look at the general syntax of the ON GOTO statement: &lt;br /&gt;
&lt;br /&gt;
 line# ON num-expr GOTO line-ref, line-ref, .... NONE line-ref &lt;br /&gt;
&lt;br /&gt;
1. The ON keyword is always separated from the GOTO keyword by a “num-expr”, or numeric expression.  (Numeric expressions can be numeric constants, numeric variables, or conditional expressions; they can also be system functions or user-defined functions, which you will learn about later in this tutorial.)  Part of the job of the ON GOTO statements is to determine the value of this numeric expression.  &lt;br /&gt;
&lt;br /&gt;
2. The “line-ref” portion of the ON GOTO statement specifies the line numbers that control should be transferred according to the value of the numeric expression.  Usually an ON GOTO statement specifies more than one line-ref; multiple line-refs must be separated with commas.  When the ON GOTO statement has determined the value of the numeric expression, it takes this number and matches it to the order of the items in the line-ref portion of the syntax. &lt;br /&gt;
&lt;br /&gt;
3. The optional “NONE line-ref” portion of the syntax indicates where program execution should go when the value of the num-expr rounds off to be less than one, or greater than the number of line-refs. &lt;br /&gt;
&lt;br /&gt;
Do not be surprised if you have just read the above explanations three or four times and still have no idea of what the ON GOTO statement actually does.  While the concept is rather simple, it can be difficult to grasp on the first explanation. &lt;br /&gt;
   &lt;br /&gt;
Let’s consider an example.  The following set of program lines prints a list of the five business days of the week on the screen and asks the operator to enter a number that signifies the current day of the week.  This number is assigned to the numeric variable DAY by the INPUT statement in line 80. &lt;br /&gt;
&lt;br /&gt;
 00010 PRINT NEWPAGE &lt;br /&gt;
 00020 PRINT “Please enter the number that signifies the current day of the week:” &lt;br /&gt;
 00030 PRINT “1 - Monday” &lt;br /&gt;
 00040 PRINT “2 - Tuesday” &lt;br /&gt;
 00050 PRINT “3 - Wednesday” &lt;br /&gt;
 00060 PRINT “4 - Thursday” &lt;br /&gt;
 00070 PRINT “5 - Friday” &lt;br /&gt;
 00080 INPUT DAY &lt;br /&gt;
 00090 ON DAY GOTO 500,1000,1500,2000,2500 &lt;br /&gt;
 00100 STOP &lt;br /&gt;
 00500 PRINT “Today is Monday” &lt;br /&gt;
 00900 STOP &lt;br /&gt;
 01000 PRINT “Today is Tuesday” &lt;br /&gt;
 01400 STOP &lt;br /&gt;
 01500 PRINT “Today is Wednesday” &lt;br /&gt;
 01900 STOP &lt;br /&gt;
 02000 PRINT “Today is Thursday” &lt;br /&gt;
 02400 STOP &lt;br /&gt;
 02500 PRINT “Today is Friday” &lt;br /&gt;
 03000 END &lt;br /&gt;
&lt;br /&gt;
Now look at the ON GOTO statement in line 90.  This statement looks up the value of DAY and matches it to the order of the line-ref specifications.  If DAY is 1 in other words, program control is transferred to the line specified by the first line-ref 500.  If DAY is 2, control goes to the line specified by the second line-ref.  Likewise, if DAY is 3, 4, or 5, control is transferred to the line specified by the third, fourth or fifth line-ref respectively. &lt;br /&gt;
&lt;br /&gt;
Type the above program lines into Business Rules! and try them out for yourself.  What happens when you type in the values 1.2, 3, 8, 3.5, and 4.6 instead of the requested information? &lt;br /&gt;
&lt;br /&gt;
What you should have discovered is that the ON GOTO statement rounds off the value of the num-expr before matching it to a line-ref.  Entering a value of 1.2 (which is rounded to 1) for instance, causes control to be transferred to the line indicated by the first line-ref.  Entering the value 3.5 (which is rounded to 4) causes control to transfer to the line indicated by the fourth line-ref. &lt;br /&gt;
&lt;br /&gt;
You should have also discovered that entering a value which rounded out to greater than 5 or less than 1 caused the program to stop altogether.  This is because program control simply transfers to the next line (which turned out to be a STOP statement in this case) when the num-expr in an ON GOTO statement doesn’t match up with the position order of any of the line-refs. &lt;br /&gt;
&lt;br /&gt;
If you wish, you can use the “NONE line-ref” portion of the ON GOTO syntax to specify where program control should go when the num-expr doesn’t match up with the line-refs.  To try the use of this parameter out, change line 90 on your screen to read as follows: &lt;br /&gt;
00090 ON DAY GOT 500,1000,1500,2000,2500 NONE 10 &lt;br /&gt;
This change will cause the program to branch back to line 10 and reprint all the instructions whenever an inappropriate value is entered for the variable DAY.&lt;br /&gt;
&lt;br /&gt;
====The ON GOSUB statement====&lt;br /&gt;
&lt;br /&gt;
The ON GOSUB statement is identical, both in syntax and in operation, to the ON GOTO statement, except for one thing:  ON GOSUB transfers program control to a complete subroutine that must end with a RETURN statement. &lt;br /&gt;
&lt;br /&gt;
Both the ON GOSUB and ON GOTO statements are frequently used to handle the branching that occurs when the operator is asked to choose one item from a menu.  In the following example, a program that figures monthly bills asks the operator which of several bills he or she wishes to figure.  An ON GOSUB statement then transfers execution to the appropriate subroutine, based on the operator’s answer (notice that the line-refs in this statement are line labels rather than line numbers).  When the subroutine is complete, a RETURN statement sends program execution back to the first statement after the ON GOSUB statement (line 140), where the operator is asked whether or not there is another bill to be figured.  As you can see from this example, the “main” part of the program is only a few lines long; most of the program is contained In the various subroutines. &lt;br /&gt;
  &lt;br /&gt;
 00010 ! ********************* B I L L S ************************* &lt;br /&gt;
 00020 ! ********PURPOSE: To figure monthly utility bills********* &lt;br /&gt;
 00030 ! CREATION DATE: 8/24/05             REVISION DATE: 8/24/05 &lt;br /&gt;
 00040 ! *********Application Development Systems, INC.*********** &lt;br /&gt;
 00050 ! ********************************************************* &lt;br /&gt;
 00060 PRINT NEWPAGE &lt;br /&gt;
 00070 PRINT “Please indicate the number of the bill you would like to figure.” &lt;br /&gt;
 00080 PRINT “1 - Electricity” &lt;br /&gt;
 00090 PRINT “2 - Natural Gas” &lt;br /&gt;
 00100 PRINT “3 - Telephone” &lt;br /&gt;
 00110 PRINT “4 - Cable TV” &lt;br /&gt;
 00120 INPUT CHOICE &lt;br /&gt;
 00130 ON CHOICE GOSUB ELEC,NATGAS,PHONE,CABLE &lt;br /&gt;
 00140 PRINT “Do you wish to figure another bill? (y/n)” &lt;br /&gt;
 00150 INPUT ANSWER$ &lt;br /&gt;
 00160 IF ANSWER$=”Y” OR ANSWER$=”y” THEN GOTO 00070 &lt;br /&gt;
 00170 STOP &lt;br /&gt;
 01000 ELEC: ! Subroutine for electricity bill &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 01650 RETURN &lt;br /&gt;
 02000 NATGAS: ! Subroutine for natural gas bill &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 02580 RETURN &lt;br /&gt;
 03000 PHONE: ! Subroutine for telephone bill &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 03890 RETURN &lt;br /&gt;
 04000 CABLE: ! Subroutine for cable TV bill &lt;br /&gt;
 o &lt;br /&gt;
 o &lt;br /&gt;
 04500 RETURN &lt;br /&gt;
 99999 END &lt;br /&gt;
  &lt;br /&gt;
====Quick Quiz 8.3====&lt;br /&gt;
1. Study the following ON GOTO statement, and then answer the questions. &amp;lt;br&amp;gt;&lt;br /&gt;
 00100 ON VAR/10 GOTO 00900, 01100,01500,02000 &lt;br /&gt;
a)   What will happen if the value of VAR/10 is 4? &amp;lt;br&amp;gt;&lt;br /&gt;
b)   What will happen if the value of VAR is 25? &amp;lt;br&amp;gt;&lt;br /&gt;
c)   What will happen if the value of VAR/10 is 16? &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. How many subroutines are referred to with line numbers in the following statement. &amp;lt;br&amp;gt;&lt;br /&gt;
 00100 ON CHOICE GOSUB 2000,3000,4000 NONE 5000&lt;br /&gt;
 &lt;br /&gt;
a)   One. &amp;lt;br&amp;gt;&lt;br /&gt;
b)   Two. &amp;lt;br&amp;gt;&lt;br /&gt;
c)   Three. &amp;lt;br&amp;gt;&lt;br /&gt;
d)   Four. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Name one frequent use of the ON GOTO and ON GOSUB statements. &lt;br /&gt;
&lt;br /&gt;
[[Answers 8.3]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===8.4 DO Loops===&lt;br /&gt;
&lt;br /&gt;
FOR/NEXT loops and GOTO can handle a lot of things you need to do in a program. Sometimes, you’ll want a loop with a little more flexibility. DO loops can do this for you since they require no line labels or numbers to execute. &lt;br /&gt;
Here’s the syntax:&lt;br /&gt;
&lt;br /&gt;
 DO WHILE condition-expression&lt;br /&gt;
or&lt;br /&gt;
 DO UNTIL condition-expression&lt;br /&gt;
&lt;br /&gt;
;The DO is always used with the LOOP statement.&lt;br /&gt;
&lt;br /&gt;
The While keyword indicates that the loop should be executed only if the specified conditional expression evaluates to true. If the conditional expression evaluates to false, execution will skip to the first line following the Loop statement. The Until keyword indicates that the loop should be executed only if the specified conditional expression evaluates to false. If the conditional expression evaluates to true, execution will skip to the first line following the Loop statement.&lt;br /&gt;
&lt;br /&gt;
Look at the example below:&lt;br /&gt;
 00005    LET X=1&lt;br /&gt;
 00010    DO WHILE X&amp;lt;10&lt;br /&gt;
 00020       PRINT &amp;quot;Hello Cat&amp;quot;&lt;br /&gt;
 00030       LET X=X+1&lt;br /&gt;
 00040    LOOP &lt;br /&gt;
Do loops continue to execute repeatedly until the condition is met. They can also be exited using the EXIT DO statement. &lt;br /&gt;
&lt;br /&gt;
====Chapter Exercises==== &lt;br /&gt;
1. Create a FOR/NEXT loop that outputs the following: &lt;br /&gt;
10 &amp;lt;br&amp;gt;&lt;br /&gt;
 7 &amp;lt;br&amp;gt;&lt;br /&gt;
 4 &amp;lt;br&amp;gt;&lt;br /&gt;
 1 &amp;lt;br&amp;gt;&lt;br /&gt;
-2 &amp;lt;br&amp;gt;&lt;br /&gt;
-5 &amp;lt;br&amp;gt;&lt;br /&gt;
-8 &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Write a program using a FOR/NEXT loop to print the following items each time through the loop: 1, 1*1, 2**1, 3***1.  The loop should be executed starting at 1 and ending with 16.&lt;br /&gt;
&lt;br /&gt;
You might want to experiment with three types of PRINT statements inside your loop.  First, try unformatted printing with a comma.  Then, run the program again with formatted printing with a FORM statement and run the program a third time.  Which do you prefer and why? &lt;br /&gt;
&lt;br /&gt;
3. Your wealthy cousin Leo (rumored to have connections with Las Zetas) has agreed to loan you $15,000 for that cabin on the lake.  The interest rate is 12% per year.  The loan is to be repaid in small monthly payments for 10 years. Let’s write a program (called a loan amortization program) to figure out how much interest will be paid in dollars. &lt;br /&gt;
&lt;br /&gt;
Use the formula for monthly payment from [[Chapter 4]].  For each of the 120 monthly payments, the money goes for two things: paying interest and reducing the principal.  Your printout should have four columns of data: &lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
|Month||Interest||Principal||Balance &lt;br /&gt;
|-&lt;br /&gt;
|Number||Paid||Repayment||Remaining &lt;br /&gt;
|-&lt;br /&gt;
|______||________||_________||_________ &lt;br /&gt;
|-&lt;br /&gt;
|1 ||512.34||36.66 ||14,963.34 &lt;br /&gt;
|-&lt;br /&gt;
|2||510.10||39.90||14,923.44 &lt;br /&gt;
|-&lt;br /&gt;
|O ||    O||    O||    O &lt;br /&gt;
|-&lt;br /&gt;
|120 ||  5.12 || 494.88 || 0.00 &lt;br /&gt;
|-&lt;br /&gt;
|______ ||________ ||_________ ||_________ &lt;br /&gt;
|-&lt;br /&gt;
| TOTAL  ||  ????????    ||   15,000.00    ||     0.00 &lt;br /&gt;
|}&lt;br /&gt;
  &lt;br /&gt;
As the example above shows, you should also compute totals for the two middle columns. &lt;br /&gt;
&lt;br /&gt;
After using the monthly payment formula once at the start of your program, the formulas that you will need inside the loop are: &lt;br /&gt;
&lt;br /&gt;
 LET INT = RATE/12 * BALANCE !      Interest paid &lt;br /&gt;
 LET REPAY = MONTHLY -  INT !       Principal repayment &lt;br /&gt;
 LET BALANCE = BALANCE - REPAY !    Balance remaining &lt;br /&gt;
&lt;br /&gt;
At the start of your program you will also need to add these statements: &lt;br /&gt;
 &lt;br /&gt;
 LET RATE = .15 !                  Interest rate 15% &lt;br /&gt;
 LET BALANCE = 1500 !         Initial amount of loan &lt;br /&gt;
 LET YEARS = 10 !                10 year loan &lt;br /&gt;
&lt;br /&gt;
How many dollars will cousin Leo make in interest on this little favor?&lt;br /&gt;
&lt;br /&gt;
[[Solutions#CHAPTER 8|Solution]]&lt;br /&gt;
&lt;br /&gt;
NEXT:[[Chapter 9|Organizing Folders and Programs]]&lt;br /&gt;
&lt;br /&gt;
[[BR Tutorial|Back to Index]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Tutorial 1]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Restore_File&amp;diff=10746</id>
		<title>Restore File</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Restore_File&amp;diff=10746"/>
		<updated>2016-06-16T20:22:27Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Syntax */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Restore File&#039;&#039;&#039; [[statement]] positions the file pointer at the start of the file for display, internal or external files; it also positions the file pointer to a specified byte for external files, or to a specified record for internal or external files. The RESTORE file statement can also be used to drop all data from any type of files opened OUTPUT SEQUENTIAL.&lt;br /&gt;
&lt;br /&gt;
# The positional parameters FIRST, LAST, PRIOR, NEXT, and SAME can now be used with the RESTORE statement, as well as with READ, DELETE and REWRITE. See the [[Read File]] statement discussion for details.&lt;br /&gt;
# In linked files, the RESTORE file statement plays two important roles. First, it can be used with the REC= parameter to reposition the file pointer to any specified record number. The number of the anchor record of a desired link list would typically be stored in the associated master record.&lt;br /&gt;
&lt;br /&gt;
If REC= specifies an anchor record KREC is set accordingly. Otherwise KREC is set to zero. The second role of RESTORE is that it can be used without parameters (or REC=0) to create a new anchor point for a linked list that you wish to add or insert. The current position of the file pointer makes no difference when RESTORE is used in this manner.&lt;br /&gt;
&lt;br /&gt;
===Comments and Examples===&lt;br /&gt;
A file must already be opened and assigned a file number before RESTORE can be used. With a display file, RESTORE moves the pointer to the beginning of the file. When used with internal or external files, RESTORE can have three functions.&lt;br /&gt;
&lt;br /&gt;
First, it can move the file pointer to the start of the file when used with the [[SEQUENTIAL]], [[RELATIVE]], or [[KEYED]] access methods.&lt;br /&gt;
&lt;br /&gt;
Second, it can move the pointer to a specified relative record number when the file is opened for RELATIVE processing and the REC= clause is specified.&lt;br /&gt;
&lt;br /&gt;
Third, it can position the index file pointer to a record with a specified key field when that file is opened for KEYED processing and a &amp;quot;KEY=&amp;quot; clause is specified.&lt;br /&gt;
&lt;br /&gt;
A fourth function, available only with external files opened for RELATIVE processing, is to position the file pointer to a specified byte number.&lt;br /&gt;
&lt;br /&gt;
Lines 300, 310, 320 and 330 illustrate these four functions, respectively.&lt;br /&gt;
&lt;br /&gt;
 00300 RESTORE #1:&lt;br /&gt;
 00310 RESTORE #2,REC=25: NOREC 920&lt;br /&gt;
 00320 RESTORE #3,KEY=CUSTNUM$: NOKEY 930&lt;br /&gt;
 00330 RESTORE #4,POS=25*RLN(4)+1: NOREC 920&lt;br /&gt;
&lt;br /&gt;
Line 300 moves the pointer to the beginning of the file for any type of file (display, internal or external) opened for INPUT. For an internal or external file opened for RELATIVE processing, line 310 moves the pointer to record number 25; the program&#039;s next sequential READ (without a REC= clause) would read record 25. If record 25 does not exist, the NOREC clause on line 310 would transfer control to line 920.&lt;br /&gt;
&lt;br /&gt;
For file #3 opened for internal KEYED processing, line 320 moves the pointer in file #3 to the first record with a key field equal to the current value of CUSTNUM$. The next sequential READ (without a KEY= clause) would read this record. If there is no match for this key value, the NOKEY clause on line 320 transfers control to line 930.&lt;br /&gt;
&lt;br /&gt;
File #4 must be opened for external RELATIVE processing to use a POS= clause. Line 330 moves invokes the RLN function to obtain the record length when file #4 was opened; it then computes 25 times this record length and adds one; finally it moves the pointer to the calculated byte number. If this byte is past the end of the file, the NOREC clause will transfer control to line 920.&lt;br /&gt;
&lt;br /&gt;
There are potential problems in using a RESTORE statement to move the pointer to the beginning of the file whenever the file is opened for OUTPUT. All data will be dropped when RESTORE is executed on files opened DISPLAY OUTPUT, or INTERNAL OUTPUT SEQUENTIAL or EXTERNAL OUTPUT SEQUENTIAL; this may not be desirable. An error will result for files opened EXTERNAL OUTPUT RELATIVE, INTERNAL OUTPUT RELATIVE or OUTPUT KEYED whenever an attempt is made to execute a RESTORE.&lt;br /&gt;
&lt;br /&gt;
===Syntax===&lt;br /&gt;
 RESTORE #&amp;lt;[[file number]]&amp;gt; {[, [[KEY]] {=|&amp;gt;=} &amp;lt;[[string expression]]&amp;gt;]|[, [[Index_Facility#Finding_records_with_the_KEY_and_SEARCH_parameters|SEARCH]] {=|&amp;gt;=} &amp;lt;[[string expression]]&amp;gt;]|[, [[REC=]]&amp;lt;[[numeric expression]]&amp;gt;]|[, [[Pos Parameter|POS]]=&amp;lt;[[numeric expression]]&amp;gt;]} [, &amp;lt;[[positional parameter]]&amp;gt;] [, {[[RESERVE]]|[[RELEASE]]}] : [&amp;lt;[[error condition]]&amp;gt; &amp;lt;[[line ref]]&amp;gt;][,...]&lt;br /&gt;
[[Image:Restorefile.png|850px]]&lt;br /&gt;
&lt;br /&gt;
===Defaults===&lt;br /&gt;
:1.) Move the pointer to the start of the file. In addition, drop the contents of the file if access is INTERNAL, OUTPUT, SEQUENTIAL, or EXTERNAL, OUTPUT, SEQUENTIAL, or DISPLAY, OUTPUT.&lt;br /&gt;
:2.) Release current lock and all previous locks.&lt;br /&gt;
:3.) Interrupt the program if an error occurs and &amp;quot;ON error&amp;quot; is not active.&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
The &amp;quot;#file-num&amp;quot; parameter is a numeric expression that references the file to be acted on. It must evaluate to a number from 0 to 127 or to 255.&lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;REC = num-expr&amp;quot; clause is used with internal or external files opened for RELATIVE processing; its purpose is to position to a specified record number. After the numeric expression is evaluated and rounded to an integer, the pointer is moved to the start of that record number. If &amp;quot;REC = num-expr&amp;quot; or &amp;quot;POS = num- expr&amp;quot; is not specified, the pointer will be moved to the start of the file (as if RESTORE #n, REC = 1 had been executed).&lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;POS = num-expr&amp;quot; clause is used only with external files opened for RELATIVE processing; its purpose is to position the file pointer to a specified byte. The numeric expression (usually a simple numeric variable or constant) is evaluated and rounded to an integer before positioning.&lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;KEY&amp;quot; and &amp;quot;SEARCH&amp;quot; parameters are used with internal files opened for KEYED processing; after the string expression is evaluated, the system reads the first record that matches the key field. If a KEY or if the SEARCH clause is not specified; the system inputs the next record in key sequence.&lt;br /&gt;
&lt;br /&gt;
For complete information about the KEY and SEARCH parameters and the &amp;quot;=&amp;quot; and &amp;quot;&amp;gt;=&amp;quot; operators (used for full and partial matches either exactly equal or &amp;quot;next greater&amp;quot;), see [[Index Facility]].&lt;br /&gt;
&lt;br /&gt;
The positional parameters that can be used with the RESTORE statementare : FIRST, LAST, PRIOR, NEXT, and SAME. Additionally the following are available  for [[System/36]] compatibility: [[RESTORE]], [[DELETE]], [[REWRITE]]&lt;br /&gt;
These may be used with Business Rules! internal files which have been opened for either RELATIVE or KEYED access, and with external files. The files must be opened for either INPUT or OUTIN. See [[Read file]] for more information.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;string-expr&amp;quot; parameter is the string that is to be matched to the key field. This specification usually takes the form of a simple string variable or constant.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;RESERVE&amp;quot; and &amp;quot;RELEASE&amp;quot; parameters specify record locking rules for multi-user systems. &amp;quot;RESERVE&amp;quot; instructs the system to hold all previous locks. &amp;quot;RELEASE&amp;quot; releases all previous locks.&lt;br /&gt;
&lt;br /&gt;
The RESTORE file statement allows error handling with the &amp;quot;error-cond line-ref&amp;quot; parameter. See [[Error Conditions]] for more information.&lt;br /&gt;
&lt;br /&gt;
===Technical Considerations===&lt;br /&gt;
# Relevant error conditions are [[ERROR]], [[EXIT]], [[IOERR]], [[NOREC]], and [[NOKEY]].&lt;br /&gt;
# Although RESTORE #1: is often used to release the record(s) locked by a workstation, REREAD #1: RELEASE is faster.&lt;br /&gt;
# When a file is opened INTERNAL OUTPUT SEQUENTIAL, EXTERNAL OUTPUT SEQUENTIAL, or DISPLAY OUTPUT, the pointer is initially positioned at the end of the file; all new records are added to the end. A RESTORE statement can override this and move the pointer to the beginning of the file. However, all the existing data is dropped (as with the DROP command) and new records are written at the beginning.&lt;br /&gt;
# If an internal file is opened OUTPUT RELATIVE or OUTPUT KEYED, the RESTORE statement cannot be used. If an external file is opened OUTPUT RELATIVE, the RESTORE statement cannot be used without a POS= clause.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:External File Processing Statements]]&lt;br /&gt;
[[Category:Internal File Processing Statements]]&lt;br /&gt;
[[Category:Statements]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Restore_File&amp;diff=10745</id>
		<title>Restore File</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Restore_File&amp;diff=10745"/>
		<updated>2016-06-16T20:22:11Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Syntax */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Restore File&#039;&#039;&#039; [[statement]] positions the file pointer at the start of the file for display, internal or external files; it also positions the file pointer to a specified byte for external files, or to a specified record for internal or external files. The RESTORE file statement can also be used to drop all data from any type of files opened OUTPUT SEQUENTIAL.&lt;br /&gt;
&lt;br /&gt;
# The positional parameters FIRST, LAST, PRIOR, NEXT, and SAME can now be used with the RESTORE statement, as well as with READ, DELETE and REWRITE. See the [[Read File]] statement discussion for details.&lt;br /&gt;
# In linked files, the RESTORE file statement plays two important roles. First, it can be used with the REC= parameter to reposition the file pointer to any specified record number. The number of the anchor record of a desired link list would typically be stored in the associated master record.&lt;br /&gt;
&lt;br /&gt;
If REC= specifies an anchor record KREC is set accordingly. Otherwise KREC is set to zero. The second role of RESTORE is that it can be used without parameters (or REC=0) to create a new anchor point for a linked list that you wish to add or insert. The current position of the file pointer makes no difference when RESTORE is used in this manner.&lt;br /&gt;
&lt;br /&gt;
===Comments and Examples===&lt;br /&gt;
A file must already be opened and assigned a file number before RESTORE can be used. With a display file, RESTORE moves the pointer to the beginning of the file. When used with internal or external files, RESTORE can have three functions.&lt;br /&gt;
&lt;br /&gt;
First, it can move the file pointer to the start of the file when used with the [[SEQUENTIAL]], [[RELATIVE]], or [[KEYED]] access methods.&lt;br /&gt;
&lt;br /&gt;
Second, it can move the pointer to a specified relative record number when the file is opened for RELATIVE processing and the REC= clause is specified.&lt;br /&gt;
&lt;br /&gt;
Third, it can position the index file pointer to a record with a specified key field when that file is opened for KEYED processing and a &amp;quot;KEY=&amp;quot; clause is specified.&lt;br /&gt;
&lt;br /&gt;
A fourth function, available only with external files opened for RELATIVE processing, is to position the file pointer to a specified byte number.&lt;br /&gt;
&lt;br /&gt;
Lines 300, 310, 320 and 330 illustrate these four functions, respectively.&lt;br /&gt;
&lt;br /&gt;
 00300 RESTORE #1:&lt;br /&gt;
 00310 RESTORE #2,REC=25: NOREC 920&lt;br /&gt;
 00320 RESTORE #3,KEY=CUSTNUM$: NOKEY 930&lt;br /&gt;
 00330 RESTORE #4,POS=25*RLN(4)+1: NOREC 920&lt;br /&gt;
&lt;br /&gt;
Line 300 moves the pointer to the beginning of the file for any type of file (display, internal or external) opened for INPUT. For an internal or external file opened for RELATIVE processing, line 310 moves the pointer to record number 25; the program&#039;s next sequential READ (without a REC= clause) would read record 25. If record 25 does not exist, the NOREC clause on line 310 would transfer control to line 920.&lt;br /&gt;
&lt;br /&gt;
For file #3 opened for internal KEYED processing, line 320 moves the pointer in file #3 to the first record with a key field equal to the current value of CUSTNUM$. The next sequential READ (without a KEY= clause) would read this record. If there is no match for this key value, the NOKEY clause on line 320 transfers control to line 930.&lt;br /&gt;
&lt;br /&gt;
File #4 must be opened for external RELATIVE processing to use a POS= clause. Line 330 moves invokes the RLN function to obtain the record length when file #4 was opened; it then computes 25 times this record length and adds one; finally it moves the pointer to the calculated byte number. If this byte is past the end of the file, the NOREC clause will transfer control to line 920.&lt;br /&gt;
&lt;br /&gt;
There are potential problems in using a RESTORE statement to move the pointer to the beginning of the file whenever the file is opened for OUTPUT. All data will be dropped when RESTORE is executed on files opened DISPLAY OUTPUT, or INTERNAL OUTPUT SEQUENTIAL or EXTERNAL OUTPUT SEQUENTIAL; this may not be desirable. An error will result for files opened EXTERNAL OUTPUT RELATIVE, INTERNAL OUTPUT RELATIVE or OUTPUT KEYED whenever an attempt is made to execute a RESTORE.&lt;br /&gt;
&lt;br /&gt;
===Syntax===&lt;br /&gt;
 RESTORE #&amp;lt;[[file number]]&amp;gt; {[, [[KEY]] {=|&amp;gt;=} &amp;lt;[[string expression]]&amp;gt;]|[, [[Index_Facility#Finding_records_with_the_KEY_and_SEARCH_parameters|SEARCH]]{=|&amp;gt;=} &amp;lt;[[string expression]]&amp;gt;]|[, [[REC=]]&amp;lt;[[numeric expression]]&amp;gt;]|[, [[Pos Parameter|POS]]=&amp;lt;[[numeric expression]]&amp;gt;]} [, &amp;lt;[[positional parameter]]&amp;gt;] [, {[[RESERVE]]|[[RELEASE]]}] : [&amp;lt;[[error condition]]&amp;gt; &amp;lt;[[line ref]]&amp;gt;][,...]&lt;br /&gt;
[[Image:Restorefile.png|850px]]&lt;br /&gt;
&lt;br /&gt;
===Defaults===&lt;br /&gt;
:1.) Move the pointer to the start of the file. In addition, drop the contents of the file if access is INTERNAL, OUTPUT, SEQUENTIAL, or EXTERNAL, OUTPUT, SEQUENTIAL, or DISPLAY, OUTPUT.&lt;br /&gt;
:2.) Release current lock and all previous locks.&lt;br /&gt;
:3.) Interrupt the program if an error occurs and &amp;quot;ON error&amp;quot; is not active.&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
The &amp;quot;#file-num&amp;quot; parameter is a numeric expression that references the file to be acted on. It must evaluate to a number from 0 to 127 or to 255.&lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;REC = num-expr&amp;quot; clause is used with internal or external files opened for RELATIVE processing; its purpose is to position to a specified record number. After the numeric expression is evaluated and rounded to an integer, the pointer is moved to the start of that record number. If &amp;quot;REC = num-expr&amp;quot; or &amp;quot;POS = num- expr&amp;quot; is not specified, the pointer will be moved to the start of the file (as if RESTORE #n, REC = 1 had been executed).&lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;POS = num-expr&amp;quot; clause is used only with external files opened for RELATIVE processing; its purpose is to position the file pointer to a specified byte. The numeric expression (usually a simple numeric variable or constant) is evaluated and rounded to an integer before positioning.&lt;br /&gt;
&lt;br /&gt;
The optional &amp;quot;KEY&amp;quot; and &amp;quot;SEARCH&amp;quot; parameters are used with internal files opened for KEYED processing; after the string expression is evaluated, the system reads the first record that matches the key field. If a KEY or if the SEARCH clause is not specified; the system inputs the next record in key sequence.&lt;br /&gt;
&lt;br /&gt;
For complete information about the KEY and SEARCH parameters and the &amp;quot;=&amp;quot; and &amp;quot;&amp;gt;=&amp;quot; operators (used for full and partial matches either exactly equal or &amp;quot;next greater&amp;quot;), see [[Index Facility]].&lt;br /&gt;
&lt;br /&gt;
The positional parameters that can be used with the RESTORE statementare : FIRST, LAST, PRIOR, NEXT, and SAME. Additionally the following are available  for [[System/36]] compatibility: [[RESTORE]], [[DELETE]], [[REWRITE]]&lt;br /&gt;
These may be used with Business Rules! internal files which have been opened for either RELATIVE or KEYED access, and with external files. The files must be opened for either INPUT or OUTIN. See [[Read file]] for more information.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;string-expr&amp;quot; parameter is the string that is to be matched to the key field. This specification usually takes the form of a simple string variable or constant.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;RESERVE&amp;quot; and &amp;quot;RELEASE&amp;quot; parameters specify record locking rules for multi-user systems. &amp;quot;RESERVE&amp;quot; instructs the system to hold all previous locks. &amp;quot;RELEASE&amp;quot; releases all previous locks.&lt;br /&gt;
&lt;br /&gt;
The RESTORE file statement allows error handling with the &amp;quot;error-cond line-ref&amp;quot; parameter. See [[Error Conditions]] for more information.&lt;br /&gt;
&lt;br /&gt;
===Technical Considerations===&lt;br /&gt;
# Relevant error conditions are [[ERROR]], [[EXIT]], [[IOERR]], [[NOREC]], and [[NOKEY]].&lt;br /&gt;
# Although RESTORE #1: is often used to release the record(s) locked by a workstation, REREAD #1: RELEASE is faster.&lt;br /&gt;
# When a file is opened INTERNAL OUTPUT SEQUENTIAL, EXTERNAL OUTPUT SEQUENTIAL, or DISPLAY OUTPUT, the pointer is initially positioned at the end of the file; all new records are added to the end. A RESTORE statement can override this and move the pointer to the beginning of the file. However, all the existing data is dropped (as with the DROP command) and new records are written at the beginning.&lt;br /&gt;
# If an internal file is opened OUTPUT RELATIVE or OUTPUT KEYED, the RESTORE statement cannot be used. If an external file is opened OUTPUT RELATIVE, the RESTORE statement cannot be used without a POS= clause.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:External File Processing Statements]]&lt;br /&gt;
[[Category:Internal File Processing Statements]]&lt;br /&gt;
[[Category:Statements]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Field_Help&amp;diff=10734</id>
		<title>Field Help</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Field_Help&amp;diff=10734"/>
		<updated>2016-05-21T15:22:08Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For disambiguation purposes, see also BRConfig.sys [[FieldHelp]]&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Field help specifications&amp;quot; portion of the full screen processing syntax identifies the user level, window placement, and text that is to be displayed in field help windows.&lt;br /&gt;
&lt;br /&gt;
It can also be used with print fields statements, for example, with buttons. &lt;br /&gt;
&lt;br /&gt;
===Comments and Examples===&lt;br /&gt;
The border type and attributes for field help windows may be specified by the BRConfig.sys FIELDHELP specification. The border types which are available for field help windows are the same as the border types which are available for regular windows.&lt;br /&gt;
&lt;br /&gt;
The following helpstring specification provides no field help text for the first through fourth fields. The fifth field has a 3 x 16 window that displays if [[USERLEVEL]] is set to either 2 or 3. Default positioning (to the right of the field if possible) is used for window placement.&lt;br /&gt;
&lt;br /&gt;
 00300 RINPUT FIELDS MAT FIELD$, HELP &amp;quot;XXXX2;Pay Frequencies: \n W - Weekly\n B - Biweekly;&amp;quot;:MAT RECORD$&lt;br /&gt;
&lt;br /&gt;
The next example provides field help text that is identical for the second and third fields. The field help window is displayed below the field if possible (Business Rules will override the specification and find a position that does work if below is not possible). NOTE that the specifications for the first and second fields use @ as the separation character, but the specification for the third field-which utilizes backwards referencing for the display of identical text -ends with a semi-colon.&lt;br /&gt;
&lt;br /&gt;
 00550 INPUT FIELDS MAT FIELD$, HELP &amp;quot;1B@Non-standard separation\ncharacter@1B@Normal is ;@&amp;amp;2;&amp;quot;: MAT RECORD$&lt;br /&gt;
   &lt;br /&gt;
Through the use of the &amp;quot;int&amp;quot; parameter, which identifies the number of an open window, the text which is specified for a field help window may be sent to an open window instead. In the following example, &amp;quot;3&amp;quot; identifies the user level for which the help text should automatically be displayed, and &amp;quot;7&amp;quot; indicates that the field help text, &amp;quot;This text...,&amp;quot; is to be displayed in open window #7. &lt;br /&gt;
&lt;br /&gt;
 00350 INPUT FIELDS &amp;quot;10,10,C 20,UAE&amp;quot;,HELP &amp;quot;37;This text would be displayed in window-num 7;&amp;quot;: SAMPLE&lt;br /&gt;
&lt;br /&gt;
===Helpstring Syntax===&lt;br /&gt;
 &amp;quot;{{1|2|3} {A|B|L|R|&amp;lt;integer&amp;gt;}[&amp;lt;|&amp;gt;] &amp;lt;separator&amp;gt; &amp;lt;text&amp;gt; &amp;lt;separator&amp;gt; |X|&amp;amp;&amp;lt;Field Num&amp;gt;;}[,...]&amp;quot; &lt;br /&gt;
[[file:helpstring.png|800px]]&lt;br /&gt;
&lt;br /&gt;
===Supplemental Syntax (&amp;quot;helpstring&amp;quot; parameter)===&lt;br /&gt;
The above syntax may be inserted where the &amp;quot;helpstring&amp;quot; parameter appears in the main diagram for full screen processing statements. If the &amp;quot;string-expr&amp;quot; or &amp;quot;MAT string-array&amp;quot; parameters are used to specify field help text, each must include the same elements that are identified in the &amp;quot;helpstring&amp;quot; specification. Business Rules assumes that multiple field help specifications will be identified in the same field order which is indicated in the field definition string.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;, and &amp;quot;4&amp;quot; HELPLEVEL parameters denote the user level for which the field should be automatically displayed. (This option works in conjunction with the WBConfig.sys file&#039;s USERLEVEL specification.) &lt;br /&gt;
*&amp;quot;1&amp;quot; indicates that the information provided in this field help text is very important and it should be automatically displayed to most users -even those who are experienced.&lt;br /&gt;
*&amp;quot;2&amp;quot; indicates that the information should be automatically displayed to anybody who is at an intermediate level (or less) of experience with the software.&lt;br /&gt;
*&amp;quot;3&amp;quot; indicates that the information should be automatically displayed only to novice users of the software.&lt;br /&gt;
*&amp;quot;4&amp;quot; supports windows tooltips, but suppresses field help windows entirely (4.2). This is the recommended setting. &lt;br /&gt;
Automatic display of all field help text, regardless of the user level specified here, can be turned off when the WBConfig.sys file&#039;s USERLEVEL specification is set to 0. Field help text remains available to all users, even if it isn&#039;t automatically displayed to them, when they press the &amp;lt;HELP&amp;gt; key. (Pressing &amp;lt;HELP&amp;gt; a second time initiates regular help processing.)&lt;br /&gt;
&lt;br /&gt;
The next block of parameters identifies the placement of the window that is to display the field help text. The letter parameters specify the following: &lt;br /&gt;
*&amp;quot;A&amp;quot; is above the field, &lt;br /&gt;
*&amp;quot;B&amp;quot; is below the field, &lt;br /&gt;
*&amp;quot;L&amp;quot; is to the left of the field, and &lt;br /&gt;
*&amp;quot;R&amp;quot; is to the right of the field. &lt;br /&gt;
A greater-than (&amp;gt;) or less-than (&amp;lt;) sign may be specified along with either A or B. Greater-than (points to the right) specifies that the window is to be placed flush right with the field. Less-than (points to the left) specifies flush left placement. When neither sign is specified, the window is centered above or below the field. Business Rules always attempt to use the specified placement instructions. However, if the amount of room on the screen does not permit honoring this specification, default placement will occur.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;int&amp;quot; parameter may also be used to identify window position. It allows field help windows to directly interact with I/O windows. &amp;quot;Int&amp;quot; represents an integer from 1 to 999 (inclusive) that identifies the number of an open window file. It causes the field help text to be sent to a window which is already displayed on the screen. If the number specified is not a valid window file, default field help window placement will occur.&lt;br /&gt;
Use of the &amp;quot;int&amp;quot; parameter can result in two major screen optimizations: &lt;br /&gt;
:a) it significantly reduces the number of times that the screen is repainted (rather than displaying a different window for each field, Business Rules just displays the open window),&lt;br /&gt;
:b) it causes Business Rules to rewrite the contents of the window only when necessary (thus when the cursor moves between two fields with the same help text, no rewrite occurs). &lt;br /&gt;
Int is particularly desirable for Unix / Linux terminals, especially when large amounts of text are being repeatedly displayed.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;sep&amp;quot; parameter represents a non-numeric and non- alphabetic character that will be used as a separator. The character, which is used, may not appear within the help text. ADS recommends the use of a semi-colon (;) for this separator if it is not required in the text. The same character which is used as the &amp;quot;sep&amp;quot; before the text must also be specified as the &amp;quot;sep&amp;quot; after the text.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;text&amp;quot; parameter represents the field help information that is to be displayed to the user. Business Rules automatically determines the width and height of the window according to the width of the lines and the number of rows of text, which are specified for this parameter. The new-line character (CHR$(10)) or a backslash and lowercase n (\n) may be used to indicate the start of a new line of text. The maximum line length for field help text is 78 characters. An error will occur when lines longer than this are specified. Although Business Rules displays up to 1000 characters of text in a field help window, 100 characters should be considered a more practical limit.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;X&amp;quot; parameter denotes a field for which there is to be no help text. It may be repeated as many times as are necessary. If you wish to provide help text for only the fourth field, you would begin the helpstring specification with &amp;quot;XXX&amp;quot; to denote that there is no field help for the first three fields.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;field-num&amp;quot; parameter may be used to specify the same text that has already been identified for an earlier field. Only backward references are allowed. &amp;quot;Field-num&amp;quot; represents the number of the field for which text has already been specified; it must be preceded by an ampersand (&amp;amp;) and followed by a semi- colon (;).&lt;br /&gt;
&lt;br /&gt;
===Defaults===&lt;br /&gt;
:1.) Center window above field.&lt;br /&gt;
:2.) R if possible; attempt B, L, then A if necessary.&lt;br /&gt;
&lt;br /&gt;
===Technical Considerations===&lt;br /&gt;
:1.)There may be more or fewer fields identified in the helpstring than there are defined in the full screen processing statement.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Help]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Print_Fields_Buttons&amp;diff=10733</id>
		<title>Print Fields Buttons</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Print_Fields_Buttons&amp;diff=10733"/>
		<updated>2016-05-21T15:16:21Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Buttons can be added to your Business Rules! program to make user input more intuitive. Buttons are made by using the &#039;&#039;&#039;B&#039;&#039;&#039; attribute on a print fields statement. They set the FKEY value which then can be used to complete an action. Keep in mind that buttons depend on something being done within the program while BR waits for the button to be pushed by the user. &lt;br /&gt;
&lt;br /&gt;
help text (tool tips) can also be used on a button. &lt;br /&gt;
&lt;br /&gt;
===Comments and Examples===&lt;br /&gt;
[[image:DoneButton.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here, the &amp;quot;Done&amp;quot; button is clicked after the user has selected the desired items. It sets FKEY to 99 and continues with to the program to WRITE a record to the file. &lt;br /&gt;
&lt;br /&gt;
 00340     print fields &amp;quot;23,30,CC 8,,b99&amp;quot; : &amp;quot;Done&amp;quot;&lt;br /&gt;
 00350     do&lt;br /&gt;
 00360        input fields &amp;quot;22,14,CHECK 8,,10;23,14,CHECK 8,,11;24,14,CHECK  8,,12&amp;quot;: Box$(1),Box$(2),Box$(3)&lt;br /&gt;
 00370        print fields &amp;quot;24,1,N 2&amp;quot;: Fkey&lt;br /&gt;
 00380     loop While Fkey~=99&lt;br /&gt;
 00390     For I=1 to UDIM(box$)&lt;br /&gt;
 00400         if box$(I)(1:1)=&amp;quot;^&amp;quot; then ordered(I)=1 else ordered(I)=0&lt;br /&gt;
 00410     next I&lt;br /&gt;
&lt;br /&gt;
Line 340 prints the button. The [[DO LOOP]] on lines 350 to 380 give the button an action to wait for: printing the [[Check Box]]es and waiting for them to be selected. The [[For]]/[[Next]] statements in lines 390 to 410 records which checkboxes were chosen. &lt;br /&gt;
&lt;br /&gt;
[[image:YesQuitButton.jpg]]&lt;br /&gt;
&lt;br /&gt;
In this example, the user can click &amp;quot;Yes&amp;quot; (which sets the FKEY value to 8 and displays the next record in the file, or &amp;quot;Quit&amp;quot;, which sets the FKEY value to 9 and will end the program. &lt;br /&gt;
&lt;br /&gt;
 00011     open #1: &amp;quot;name=orders.INT, kfname=firstlast.int,kps=1,kln=60&amp;quot;, internal, input, keyed&lt;br /&gt;
 00012     print fields &amp;quot;17,2,c 15&amp;quot;:&amp;quot;Next record?&amp;quot;&lt;br /&gt;
 00013     print fields &amp;quot;18,2,cc 10,,b8&amp;quot;:&amp;quot;Yes&amp;quot;&lt;br /&gt;
 00014     print fields &amp;quot;18,14,cc 10,,b9&amp;quot;:&amp;quot;Quit&amp;quot;&lt;br /&gt;
 00015  !&lt;br /&gt;
 00016      read #1, using READFORM, search=Lastname$: First$,Last$,Address$,City$,State$,Zipcode$,Shipmethod$,Item1,Item2,Item3&lt;br /&gt;
 00017    READFORM: form C 30,C 30,C 30,C 15,C 2,C 7,C 1,N 1,N 1,N 1&lt;br /&gt;
 00018      print fields Mat Prinform$: &amp;quot;Name: &amp;quot;,First$,&amp;quot; &amp;quot;,Last$,&amp;quot;Address: &amp;quot;,Address$,&amp;quot;City: &amp;quot;,City$,&amp;quot;State: &amp;quot;,State$,&amp;quot;Zipcode: &amp;quot;,Zipcode$&lt;br /&gt;
 00019      print fields Mat Prinform2$: &amp;quot;Overnight or Regular? &amp;quot;,  Shipmethod$,&amp;quot;Item 1? &amp;quot;,Item1,&amp;quot;Item 2? &amp;quot;,Item2,&amp;quot;Item 3? &amp;quot;,Item3&lt;br /&gt;
 00020  !&lt;br /&gt;
 00021  !   Prinform2: Form &amp;quot;11,2,c 22&amp;quot;,&amp;quot;11,25,c 1&amp;quot;,&amp;quot;13,2,c 8&amp;quot;,&amp;quot;13, 12,n 1&amp;quot;,&amp;quot;14,2,c 8&amp;quot;,&amp;quot;14,12,n 1&amp;quot;,&amp;quot;15,2,c 8&amp;quot;,&amp;quot;15,12,n 1&amp;quot;&lt;br /&gt;
 00022  again: !&lt;br /&gt;
 00023      do&lt;br /&gt;
 00024        input fields &amp;quot;24,1,c 1&amp;quot;: nomatter$&lt;br /&gt;
 00025      loop until fkey=8 or fkey=9&lt;br /&gt;
 00026  !&lt;br /&gt;
 00027     if FKEY=8 then&lt;br /&gt;
 00028       read #1, using READFORM:  First$,Last$,Address$,City$,State$,Zipcode$,Shipmethod$,Item1,Item2,Item3&lt;br /&gt;
 00029       print fields Mat Prinform$: &amp;quot;Name: &amp;quot;,First$,&amp;quot; &amp;quot;,Last$,&amp;quot;Address: &amp;quot;,Address$,&amp;quot;City: &amp;quot;,City$,&amp;quot;State: &amp;quot;,State$,&amp;quot;Zipcode: &amp;quot;,Zipcode$&lt;br /&gt;
 00030       print fields Mat Prinform2$: &amp;quot;Overnight or Regular? &amp;quot;, Shipmethod$,&amp;quot;Item 1? &amp;quot;,Item1,&amp;quot;Item 2? &amp;quot;,Item2,&amp;quot;Item 3? &amp;quot;,Item3&lt;br /&gt;
 00031       goto again&lt;br /&gt;
 00032     else end&lt;br /&gt;
&lt;br /&gt;
Lines 13 and 14 print the buttons, then the [[DO LOOP]] in lines 23 to 25 wait for the user to click on one or the other. The &amp;quot;Yes&amp;quot; button returns control to the program in lines 27 to 31, while if FKEY equals 9 or anything else, it ends, on line 32.&lt;br /&gt;
&lt;br /&gt;
===Syntax===&lt;br /&gt;
&lt;br /&gt;
The Button&#039;s syntax is the same as the [[Print Fields]] syntax below. However, the [[Field Spec]] parameter must also include a &#039;&#039;&#039;B&#039;&#039;&#039; attribute followed by the desired FKEY value, as shown below.&lt;br /&gt;
&lt;br /&gt;
;Print Fields Syntax:&lt;br /&gt;
 PRINT [#&amp;lt;window number&amp;gt;,] FIELDS {[[Mat]] &amp;lt;[[array name]]&amp;gt;|&amp;lt;[[string expression]]&amp;gt;|&amp;quot;&amp;lt;[[Field Specs|field spec]]&amp;gt;[;...]&amp;quot;} : {&amp;lt;data item&amp;gt;|[[Mat]] &amp;lt;[[array name]]&amp;gt;}[,...] [&amp;lt;[[error condition]]&amp;gt; &amp;lt;[[line ref]]&amp;gt;][,...]&lt;br /&gt;
&lt;br /&gt;
[[image:Printfields.png|800px]]&lt;br /&gt;
&lt;br /&gt;
;Field Spec parameter for buttons:&lt;br /&gt;
 &amp;quot;&amp;lt;row&amp;gt;,&amp;lt;column&amp;gt; &amp;lt;[[form spec]]&amp;gt; &amp;lt;field length&amp;gt;, [&amp;lt;[[attributes]]&amp;gt;,] B &amp;lt;fkey&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[image:Buttons.png|800px]]&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
;Print Fields Parameters:&lt;br /&gt;
The &amp;quot;#wind-num&amp;quot; parameter represents the file number of a window which has already been opened by an OPEN window statement. When this parameter is used, Business Rules! inputs to and outputs from the window as if it were a separate screen: the first row and column of the window are considered row 1 and column 1.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;FIELDS&amp;quot; is a required keyword which signals that data is to be printed to specific fields on the screen. It must be followed by one of three possible parameters, each of which defines the fields to be used for input.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;MAT string-array&amp;quot; parameter indicates that multiple field definitions are located in the specified string array. The array must contain all the same elements that are identified in the &amp;quot;field-spec&amp;quot; parameter.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;string expression&amp;quot; parameter may also be used to define the input fields, but its value must also contain all the same elements that are identified in the &amp;quot;field-spec&amp;quot; parameter.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;field-spec&amp;quot; parameter represents a separate syntax (see below) that identifies the following for each input field: row number; column number; format type, length and fraction length (if required) of the data to be input; and the monochrome and/or color attributes which are to be used for the field (control attributes are ignored), in this case &#039;&#039;&#039;B&#039;&#039;&#039; gives the field its &amp;quot;button&amp;quot; look.&lt;br /&gt;
&lt;br /&gt;
See [[Format Specifications]] and [[File I/O]] for information about the format specifications which may be used with the PRINT FIELDS statement.&lt;br /&gt;
&lt;br /&gt;
After the required colon, at least one &amp;quot;data-item&amp;quot; or &amp;quot;MAT array-name&amp;quot; is required. These two parameters represent the words which will display on the button. Multiple variables must be separated by commas.&lt;br /&gt;
&lt;br /&gt;
PRINT FIELDS provides error processing with the optional &amp;quot;error-cond line-ref&amp;quot; parameter. See [[Error Conditions]] for more information.&lt;br /&gt;
&lt;br /&gt;
;Field Spec Parameters:&lt;br /&gt;
&lt;br /&gt;
If the &amp;quot;string-expr&amp;quot; or &amp;quot;MAT string-array&amp;quot; parameters are used to specify the Field Spec definition, each must include the same elements identified below:&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;row&amp;quot; parameter is a required integer value that indicates the row number on the screen or in the window where the data is to be entered.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;column&amp;quot; parameter is a required integer value that indicates the starting column number on the screen where data is to be entered.&lt;br /&gt;
&lt;br /&gt;
The next set of parameters specifies the format type of the data to be entered. There are three possible routes.&lt;br /&gt;
In the top route, &amp;quot;form-spec&amp;quot; represents either a numeric or string format specification. G, GL, GU, GZ, L, N, and NZ are all valid in this position for numeric fields;  C, CC, CR, CL, CU, G, GL, GU, GZ, V, VL and VU are all valid in this position for string fields. The specification must be followed by a space.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;field-length&amp;quot; parameter, which is an integer value that identifies the length (including decimal point and decimal positions) of the field, comes next. If the field contains decimal positions, &amp;quot;fraction&amp;quot; should identify how many there are; this parameter must be separated from the field length by a period (no spaces).&lt;br /&gt;
&lt;br /&gt;
See [[Field specifications]] and [[Format specifications]] for additional information about all the format specifications listed in this section.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;attributes&amp;quot; parameter represents an insertable syntax that identifies the appearance and control attributes that are to be used for the field. See [[Attribute (Screen)]] for details.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;B&amp;quot; will give the field it&#039;s button appearance and the following FKEY number will set the value which initiates the button&#039;s action. For example:&lt;br /&gt;
&lt;br /&gt;
 00050     print fields &amp;quot;10,5,cc 10,,b9&amp;quot;:&amp;quot;Quit&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Will set the FKEY value to 9.&lt;br /&gt;
&lt;br /&gt;
===Defaults===&lt;br /&gt;
:1.) Output to the full screen (not a window).&lt;br /&gt;
:2.) Interrupt the program if an error occurs and &amp;quot;ON error&amp;quot; is not active.&lt;br /&gt;
:3.) Fraction length=0.&lt;br /&gt;
:4.) Maximum DIM length.&lt;br /&gt;
:5.) Use current attributes.&lt;br /&gt;
&lt;br /&gt;
===Technical Considerations===&lt;br /&gt;
:1.) Relevant error conditions are: [[CONV]], [[ERROR]], [[EXIT]], [[HELP]], [[IOERR]], and [[SOFLOW]].&lt;br /&gt;
:2.) When [[Option (Config)|OPTION]] INVP is in effect, the normal printing of commas and periods is interchanged in PIC, N, NZ, L, G and GZ [[format specifications]] to produce European-style numbers. &lt;br /&gt;
:3.) See [[Functions]] for information about [[CNT]], which applies to errors in field definition arrays used in full screen processing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Widget]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=LTrm$&amp;diff=10732</id>
		<title>LTrm$</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=LTrm$&amp;diff=10732"/>
		<updated>2016-05-12T20:33:06Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; LTRM$(&amp;lt;string&amp;gt;,&amp;quot;&amp;lt;chr&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
The [[LTrm$]] [[internal function]] deletes leading blanks from the variable. So named, because it &#039;&#039;left-trims&#039;&#039; the blanks from the string.&lt;br /&gt;
&lt;br /&gt;
====Comments and Examples====&lt;br /&gt;
&lt;br /&gt;
When an operator enters a character string which will be used as a key field (such as last name), any spaces on the front part of the name will probably cause the string entered to not match anything in the key file. To minimize these errors, the program can remove any leading spaces with the LTRM$ function. However, when LTRM$ successfully removes one or two spaces from the beginning of the string, this causes another problem because now the string is one or two characters shorter; this second problem can be solved by adding spaces on the right with the RPAD$ function. Combining these two functions as in line 430 below is a common data clean-up technique.&lt;br /&gt;
&lt;br /&gt;
An optional second parameter (&amp;quot;char&amp;quot;) has been added to LTRM$ and RTRM$ to specify the character to strip (instead of blanks, which are still the default). The &amp;quot;char&amp;quot; parameter is limited to one character in length (error 0410 will result if it is longer). Nulls and CHR$(0) are allowed. The following statement would return the value 12:&lt;br /&gt;
&lt;br /&gt;
 00410 PRINT FIELDS &amp;quot;10,30,C 20: &amp;quot;Enter LAST NAME&amp;quot;&lt;br /&gt;
 00420 INPUT FIELDS &amp;quot;12,30,C 10,R&amp;quot;: LNAME$&lt;br /&gt;
 00430 LET LNAME$ = RPAD$(LTRM$(LNAME$),10)&lt;br /&gt;
 00440 READ #2,USING 450,KEY=LNAME$: ADDRESS$,CITY$,ST$&lt;br /&gt;
&lt;br /&gt;
====Related Functions====&lt;br /&gt;
&lt;br /&gt;
See [[RTRM$]] to trim blanks from the right and [[LPAD$]] and [[RPAD$]] to add blanks.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Internal Functions]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10692</id>
		<title>ScreenIO Library</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=ScreenIO_Library&amp;diff=10692"/>
		<updated>2015-11-06T16:40:25Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Combo Box */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;ScreenIO Library&#039;&#039;&#039; is a Rapid Application Design tool that enables [[Sage AX]] to create complete custom programs for a fraction of the time required by traditional development. For example, a fully functional File Maintenance program can now be created in a day. A zoom function or any other &amp;quot;single screen&amp;quot; program can be created in minutes.&lt;br /&gt;
&lt;br /&gt;
These &amp;quot;screen functions&amp;quot; integrate directly with your existing database and can be implemented as a standard BR library anywhere in your existing software. Some of our customers have placed them on tabs in already existing &amp;quot;tabbed windows&amp;quot; (or new tabbed windows). Some of our customers used them to quickly spruce up the look and feel of programs designed and written for older versions of BR, with modern new gui controls.&lt;br /&gt;
&lt;br /&gt;
Just about any business application can be designed faster, cheaper, and easier using ScreenIO, than ever before. You can even build entire application suites out of &amp;quot;Screen Functions&amp;quot;. Sage recently wrote our entire internal accounting system using &amp;quot;screen function&amp;quot; technology, in just a couple of weeks.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a sister library to the [[FileIO Library]]. The ScreenIO library builds upon and requires the FileIO library in order to run. &lt;br /&gt;
&lt;br /&gt;
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.&lt;br /&gt;
&lt;br /&gt;
== Bookmarks ==&lt;br /&gt;
&lt;br /&gt;
Before we get any farther, if you&#039;re here for help with ScreenIO, here&#039;s a short list of common reference links:&lt;br /&gt;
&lt;br /&gt;
[[#ScreenIO Runtime Engine Library Functions|ScreenIO&#039;s fnFm Parameter List]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ScreenIO Events|Custom Function - Events]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Writing Screen Helper Functions|Custom Function - Parameters]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Working with the ScreenIO Loading Icon|Animations]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#ExitMode|ExitMode]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Recent Changes|Recent Changes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.&lt;br /&gt;
&lt;br /&gt;
=== Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== What is a Screen Function? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a complete self contained program, that can be chained to, procced to, run as a regular program, or even run as a library from right in the middle of your existing program.&lt;br /&gt;
&lt;br /&gt;
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This &amp;quot;Listview Screen&amp;quot; can also have buttons that chain to other screens, such as an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a &amp;quot;Customer Selection&amp;quot; listview in your other programs? No problem, the same &amp;quot;Screen Function&amp;quot; program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.&lt;br /&gt;
&lt;br /&gt;
So a Screen Function is more than a program. Its a program and a library, a gui, a complete software generation system, and an easy way to write beautiful software in BR that can be implemented again and again in your programs.&lt;br /&gt;
&lt;br /&gt;
A Screen Function is a totally modular object. Its easy to add a screen to an existing program, or to another screen. By combining multiple screens you can create truly amazing effects.&lt;br /&gt;
&lt;br /&gt;
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!&lt;br /&gt;
&lt;br /&gt;
==== How does it work? ====&lt;br /&gt;
&lt;br /&gt;
Using our powerful ScreenIO Programming System, we create the Screen and save it in an internal data file that keeps track of what data needs to be displayed where on the screen, where it needs to be saved on the disk, and what we want to do with it. We can even embed function calls and business logic directly in the screens. When we &amp;quot;compile&amp;quot; the screens, a screen helper library is created with all the custom function code that needs to run from your screen. This helper library also serves as the program you can use to run your screens.&lt;br /&gt;
&lt;br /&gt;
By keeping the screen layout in data files, it becomes easy to modify and easy to maintain. By making the screens run as library functions, they become easy to implement anywhere in your existing programs. All you have to do is create the library linkage and call the program with the following two lines of BR code:&lt;br /&gt;
&lt;br /&gt;
  LIBRARY &amp;quot;screenio&amp;quot; : fnfm$&lt;br /&gt;
  let Result$=fnfm$(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Result$ can be queried to see what the user did in the screen. A listview selection screen will return the record selected. An Add/Edit screen will directly write the results to the data file for you, and return the key to this new record in Result$. If the user cancels, Result$ will be empty.&lt;br /&gt;
&lt;br /&gt;
==== What can a Screen Function Do? ====&lt;br /&gt;
&lt;br /&gt;
A Screen Function can do many things. A Screen Function right now generally fits into three categories:&lt;br /&gt;
&lt;br /&gt;
  1. A Listview Screen Function&lt;br /&gt;
  2. An Add/Edit Screen Function&lt;br /&gt;
  3. A Menu/Simple Screen Function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Listview Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is a Screen Function that is tied to a data file (through fileIO) and has no editable text controls on it, and has a Listview on it somewhere.&lt;br /&gt;
&lt;br /&gt;
A Listview Screen Function is now the very easiest way to implement 2D Controls in your BR programs. A ListView Screen Function displays all or some of the records in a data file and allows the user to select one. In your Listview screen, you may also have a link to the add/edit screen for the same data file, creating a basic File Maintenance program. You can use your Listview Screen anywhere that you would like the user to select a record from the ListView Screen&#039;s Target File. If it is tied to an Add/Edit screen, you may also use it as the File Maintenance program for that screen. You can use the same screen in multiple ways.&lt;br /&gt;
&lt;br /&gt;
===== Add/Edit Screen Function =====&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is a screen function that is tied to a data file (through fileIO) and has editable text controls on it, and no Listivew control on it anywhere. An Add/Edit screen can be passed a key, which will cause it to act as an Edit Screen Function, telling ScreenIO to edit the record who&#039;s key was passed in. If the Add/Edit screen is not passed in a key, it will act as an Add Screen Function, telling ScreenIO to Add a new record to the data file.&lt;br /&gt;
&lt;br /&gt;
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== A Menu/Simple Screen Function =====&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple Screen Function is a screen function that is not tied to any data file. This sort of screen is very limited in functionality. The primary purpose of using such a screen is to create a menu of buttons that call other screens or other programs or library functions or parts of your code.&lt;br /&gt;
&lt;br /&gt;
A Menu/Simple screen function cannot change any data on disk because it is not tied to a data file. It is also not possible to get a lot of information back from the user in a Simple Screen Function, because instead of returning a key to a record in a data file that was edited (like an Add/Edit screen function would), a Menu/Simple screen is limited to returning a 255 byte string for its return value.&lt;br /&gt;
&lt;br /&gt;
=== Implementation Guide ===&lt;br /&gt;
&lt;br /&gt;
Implementing your new Screen Functions in your existing programs is simple, modular, and flexible. The same screen can be used in multiple places in your program suite. Any changes or bug fixes to your Screen Function change it everywhere that it is used, thanks to the power of Libraries.&lt;br /&gt;
&lt;br /&gt;
If you order a screen function from Sage AX, we will send you information explaining how to implement it. If you want to read about all the various ways to implement a screen, read on. If you are unsure what one of the options means, don&#039;t worry about it. If you buy a screen from Sage AX, we&#039;ll tell you which options apply to your screen.&lt;br /&gt;
&lt;br /&gt;
==== Installing your new screen ====&lt;br /&gt;
&lt;br /&gt;
When you order a screen, Sage will send you the following files:&lt;br /&gt;
&lt;br /&gt;
  data\screenio.dat     - Screen Header Data file containing your new screen and all your old screens&lt;br /&gt;
  data\screenio.key     - Screen Header Key file&lt;br /&gt;
  data\screenfld.dat    - Screen Fields Data file containing all the fields for your screens&lt;br /&gt;
  data\screenfld.key    - Screen Fields Key file&lt;br /&gt;
  data\screenfld.ky2    - Screen Fields Key file&lt;br /&gt;
 &lt;br /&gt;
  screenio.br           - Free ScreenIO Runtime Library required to run your  screens&lt;br /&gt;
  screenio\scrnname.br  - Screen helper library (compiled in a br program)&lt;br /&gt;
  screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;scrnname&amp;quot; is replaced by the name of your new screen.&lt;br /&gt;
&lt;br /&gt;
To begin using your new screens, simply copy the files into the main folder of your BR programs.&lt;br /&gt;
&lt;br /&gt;
==== Running your new screen ====&lt;br /&gt;
&lt;br /&gt;
You can now run your new screen by simply typing:&lt;br /&gt;
&lt;br /&gt;
  LOAD scrnname&lt;br /&gt;
  RUN&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from your existing programs ====&lt;br /&gt;
&lt;br /&gt;
However, to really get the most mileage out of your screen functions, you should implement them as library calls. This will enable you to interpret the result of the users action in the screen and act accordingly.&lt;br /&gt;
&lt;br /&gt;
To implement your new screens as library calls from within your existing programs, all you need to do is add a library statement to the ScreenIO runtime library, and call your screens.&lt;br /&gt;
&lt;br /&gt;
  01000 LIBRARY &amp;quot;screenio&amp;quot; : fnfm&lt;br /&gt;
  01200 let fnfm(&amp;quot;scrnname&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
When your program gets to line 1200, your screen is loaded and displayed, and the user is able to do anything your screen is set up for them to do. When they are done, control returns to your program at the line after 1200.&lt;br /&gt;
&lt;br /&gt;
==== Calling your screen from an existing non-gui program ====&lt;br /&gt;
&lt;br /&gt;
Calling a screen from a Non Gui program is the same as calling it from a GUI program. When a ScreenIO screen loads, the first thing it does is check if Gui is on. If its not, then it saves everything on the screen, and then turns GUI on to run your ScreenIO screen. When your screenio screen finishes running its closed, and the previous state of the screen is restored. GUI is turned off, and the text that was there is printed back on the screen.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using BR 4.2 or higher, thats all you need to do. If you&#039;re using BR 4.1 and GUI OFF and you have a non-standard sized screen (not the default of 24 x 80), then you&#039;ll also have to set env$(&amp;quot;screenrows&amp;quot;) and env$(&amp;quot;screencols&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== Returning Information from your screen ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library can return limited information about the execution of each screen. This return string is limited to 255 characters, and is generally used to return the key of the record edited/added/selected from the listview. If a Cancel option is available in your screen, and the user cancels, then the return will be blank.&lt;br /&gt;
&lt;br /&gt;
ScreenIO Returns the key of the record, by default. If you just draw a screen, and tie some fields from the file to it, writing no custom code at all, the key of the edited record will be the return value.&lt;br /&gt;
&lt;br /&gt;
However, by placing custom code in your screen, it is possible to override the default return value for your Screen Function with any kind of data you want.&lt;br /&gt;
&lt;br /&gt;
In general, if you want to use your screen to query the user for information that does not get saved in your system, then you create a screen and tie it to a temporary data file. In your calling program, you call the screen, and if the user did not cancel, you use that key to read the results from the temporary data file and interpret them, deleting the information from the file when you&#039;re done.&lt;br /&gt;
&lt;br /&gt;
However, if the amount of information you wanted to return was less then 255 bytes, it would be possible to override the return value for the screen to just return all that information in a string of data that could be interpreted by your calling program.&lt;br /&gt;
&lt;br /&gt;
=== Advanced Screen Implementation ===&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Functions ====&lt;br /&gt;
&lt;br /&gt;
There are a few other useful functions in the ScreenIO Runtime Engine Library. They are all used to display and pass control to your screen, your screen but with a few different options:&lt;br /&gt;
&lt;br /&gt;
*fnfm(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm returns true if a record was selected/edited and false if the record was not edited. If the return value for the screen is numeric, then fnfm would return the numeric return value of the screen. If the return value is a string, calling fnfm will discard the string return value and return only 1 if the user didn&#039;t cancel, or 0 if they did.&lt;br /&gt;
&lt;br /&gt;
*fnfm$(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow, DisplayOnly,Dontredolistview,Recordval,Mat Passeddata$,Usemyf,Mat Myf$,Mat Myf,Path$,Selecting) - Displays and passes control to your screen. FnFm$ returns the key of the record selected/edited, or blank if the user cancelled out of the screen. It is possible to override the return value in the screen by adding custom code to your screen. If the return value for a screen is numeric, then fnfm$ returns &amp;quot;str$()&amp;quot; of the numeric return value of the screen. Use &amp;quot;val()&amp;quot; to turn it back into a number if you need.&lt;br /&gt;
&lt;br /&gt;
*fnDisplayScreen(&amp;quot;scrnname&amp;quot;; key$, row, col, ParentKey$, ParentWindow,Recordval) - Deprecated, use fnfm instead, with the Display Only parameter. (This displays a screen, but does not pass control to it. This sort of functionality is very useful for advanced implementation of your screens in your programs. Oftentimes it is desirable, especially with a listview screen, to display a listview of items on the screen but not edit it yet. In that situation, you would want to continue in your main program, and wait until the user clicked on your listview Screen Function, at which point you would then call fnfm or fnfm$ for the same screen, allowing the user to use the listview later. The return value for fnDisplayScreen is the window number of the new Screen Function Window opened. When you are done displaying the Listview Screen Function and want to erase it, simply close the window number that fnDisplayScreen returned.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Within ScreenIO you may call screen functions from any existing screen function by placing the internal syntax for calling a screen directly in the click event for any button or any other event in your screen. This would be in the form [SCRNNAME(Row,Col)]Key$=&amp;quot;blah&amp;quot; : ParentKey$=&amp;quot;blahblah&amp;quot;. Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.&lt;br /&gt;
&lt;br /&gt;
The simplest (and most common) form is just to say [SCRNNAME]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Runtime Engine Library Function Parameters ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Functions listed above all accept the following parameters:&lt;br /&gt;
&lt;br /&gt;
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. If you are using fnCallScreen$, it is also possible to substitute the internal screenio syntax for calling screens here, which is [SCRNNAME(Row,Col)].&lt;br /&gt;
&lt;br /&gt;
*Key$ - This is the key of the current record you are editing. ScreenIO interprets this variable when it is loading and displaying your screen. If it is blank, it does not read the screen, and instead performs the screen&#039;s initialize event, the custom code (if there is any) for initializing a new record into the data file. However, if a key IS given, then instead it reads that record from the data file, performs the input, and saves the data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; A Key should never be passed into a Listview screen&#039;&#039;&lt;br /&gt;
  &lt;br /&gt;
*Row, Col - These scalar parameters represent the physical location to place the top left corner of your screen. If no Row or Col is specified, then the screen opens in the middle of your BR window, resizing Window 0 if necessary to display your entire screen. If you DO give a Row and Col value, then it is your responsibility to make sure the Screen Function fits in the BR window - otherwise you will get the BR Internal Error for invalid Row and Col specification when you try to run the screen.&lt;br /&gt;
  &lt;br /&gt;
*ParentKey$ - This is an extra value you can pass into your screen function. It is ignored by the ScreenIO Runtime Engine Library, but it may be used by your custom functions. Most often it is used by the filter event of a listview, to limit the records in the Listview. (If a Listview has no filter event defined, then by default every record of the data file is displayed).&lt;br /&gt;
  &lt;br /&gt;
*ParentWindow - This optional parameter is used in conjunction with Row and Col to specify the parent window for the Screen Function. If no Parent Window is given, then window 0 is assumed to be the parent, and the new Screen Function opens on top of whatever other windows may have been on your screen before. If a Parent Window is given, then that Parent Window is used for the Row and Col position of your screen.  &lt;br /&gt;
  &lt;br /&gt;
*DisplayOnly - This optional Boolean Flag tells the ScreenIO Runtime Engine Library to display the screen and then exit without passing control to the screen. This parameter makes FnFm, FnFm$, and fnCallScreen$ work the same way that fnDisplayScreen works above. In the case of FnFM, the return value becomes the window number of the newly opened Screen Function. In the case of FnFM$ and FnCallScreen$, the return value becomes the &amp;quot;str$()&amp;quot; value of the window number of the newly opened Screen Function - use &amp;quot;val()&amp;quot; to get the actual Window Number as a numeric value.&lt;br /&gt;
&lt;br /&gt;
*DontRedoListview - This optional boolean parameter is used when running a screen from within another screen, for example in one of your custom functions. If the calling screen has a listview on it, the Listview will automatically be repopulated when you return. If you&#039;re calling a screen that doesn&#039;t change the contents of the listview then its better not to repopulate the listview, in order to make your screens run as quickly as possible. Use this boolean flag to instruct ScreenIO not to redraw the listview you&#039;re returning &#039;&#039;&#039;&#039;&#039;to&#039;&#039;&#039;&#039;&#039;. If you&#039;re implementing a screen that Sage AX made for you, we will have already set this for you.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#039;&#039;&#039;&#039;&#039;Example:&#039;&#039;&#039; If you&#039;re in a listview screen and its calling an add/edit screen, this parameter is used on the call to the &#039;&#039;&#039;add/edit screen&#039;&#039;&#039; but it applies to the &#039;&#039;&#039;listview screen.&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave &amp;quot;Key$&amp;quot; blank.&lt;br /&gt;
&lt;br /&gt;
*Mat PassedData$ - Mat PassedData$ is an array you can use for passing Custom Information into your screens. Any of the functions inside the screen will have access to Mat PassedData$. If you&#039;re implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.&lt;br /&gt;
&lt;br /&gt;
*UseMyF - If you set this boolean parameter to True then you can pass in your own mat F$ and mat F arrays. Instead of reading the record from the disk, ScreenIO will use the record in the arrays you&#039;re passing in. Use this for an Add/Edit screen when you don&#039;t want ScreenIO to read or write the record on disk.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF$ - This is the corresponding string array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Mat MyF - This is the corresponding numeric array containing information from a record you want to edit with a screenio screen. Use with the UseMyF parameter above.&lt;br /&gt;
&lt;br /&gt;
*Path$ - This is the FileIO Path$ Parameter that specifies a Data Path to be prepended to the path specified in your file layouts, in order to accommodate situations where the same data file with the same layout occurs in multiple paths.&lt;br /&gt;
&lt;br /&gt;
*Selecting - This is a flag you can use to signal to your screens when you&#039;re running them as to the intentions of your users. You can use it to define different &amp;quot;modes&amp;quot; for the current screen. The parameter is not used by ScreenIO at all, but simply passed onto your functions, similar to the way ParentKey$ works.&lt;br /&gt;
&lt;br /&gt;
=== How does it work Internally ===&lt;br /&gt;
&lt;br /&gt;
==== Program Flow ====&lt;br /&gt;
&lt;br /&gt;
When you call your new screen, no matter how it is called, the screen layout is loaded from the screenio data files (ScreenIO.DAT and ScreenFld.DAT). Then, if a file layout is given, the file is opened, and if there is a key given, then the key is read and the read event is triggered. If a key is not given, then the initialize event is triggered.&lt;br /&gt;
&lt;br /&gt;
After that ScreenIO maps the fields in the data file onto the fields on your screen and displays them, allowing the user to interact with the screen as they wish. The screen remains in control until &amp;quot;[[#ExitMode|ExitMode]]&amp;quot; is triggered, either from one of the events, or by pressing the ESC key to trigger an [[#ExitMode|ExitMode]] of Cancel (by default), or the ENTER key to trigger an [[#ExitMode|ExitMode]] of Select (by Default).&lt;br /&gt;
&lt;br /&gt;
Once a Screen Function Event has been triggered that sets [[#ExitMode|ExitMode]] to one of the various valid exit modes, the screen is exited, and depending on [[#ExitMode|ExitMode]], the return value is calculated and the data is saved or added, or dropped, or ignored, and the return value is set. The Prewrite Event and the Exit event is triggered here.&lt;br /&gt;
&lt;br /&gt;
==== Philosophy ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO is a modular event driven system for BR. The ScreenIO Design and Runtime Libraries do for BR what Visual Basic did for the Microsoft world of programming. However, its easier to create and use ScreenIO screens then it is to write VB programs, because BR is simpler then VB in many of its internal working details, and because ScreenIO screens have the ability to write to your data files without having a stitch of custom code.&lt;br /&gt;
&lt;br /&gt;
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.&lt;br /&gt;
&lt;br /&gt;
ScreenIO cannot make every program in the world. I would be very impressed if I saw someone make a video game in ScreenIO. It is limited to interfaces that BR can produce, and that means that you can only input from one screen at a time (because BR&#039;s input statement is Modal). It can only make BR style listviews and grids, and your interfaces work using rows and columns, instead of twips or pixels like other languages.&lt;br /&gt;
&lt;br /&gt;
Instead, ScreenIO&#039;s focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can&#039;t make absolutely everything - if it could, it would become unruly and difficult to use. By limiting the scope, however, we are able to create 90% of business programs, much faster and easier then ANY other method of programming on the market.&lt;br /&gt;
&lt;br /&gt;
==== Modular ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Modular, it is extremely easy to implement your screens in any of your existing programs using the chain statement, or more commonly, a library function call. Your screens can be called from each other, even recursively should you so desire.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Event Driven ====&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.&lt;br /&gt;
&lt;br /&gt;
Each ScreenIO Screen Function has several events, that can be used to extend the functionality of your screen, provide custom validation, provide custom filtering on a Listivew, extend functionality by linking to additional screens, and control and override the return values of your Screen Functions.&lt;br /&gt;
&lt;br /&gt;
Your Screen Functions have the following events that can each be overridden with custom code, a library call, an execute command, or a link to another screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Screen Events =====&lt;br /&gt;
&lt;br /&gt;
*Enter Event: This event is triggered when your screen is first displayed.&lt;br /&gt;
&lt;br /&gt;
*Initialize Event: This event is triggered any time you call your screen without giving it a key$ (as long as there is a data file). The initialize event is used to initialize the values for newly added records in one of your data files, in an Add/Edit Screen.&lt;br /&gt;
&lt;br /&gt;
*Read Event: This event is triggered when your screen reads the initial record, and in a Listview screen, any time the Listview selection is changed. It is primarily used for unpacking the data and placing it on a screen.&lt;br /&gt;
&lt;br /&gt;
*Write Event: This event is triggered when the user selects the &amp;quot;Save&amp;quot; option in your screen, just before actually saving the data to the disk. In the Write event, you can cancel the users exiting of the screen, or change the exit mode to any other exit mode you like. You can also make any last minute changes to the data before it is saved to the disk.&lt;br /&gt;
&lt;br /&gt;
*Mainloop Event: This event is triggered every time the main Rinput Fields statement is passed. You can use this event to update information on the screen, implement special keys, or implement windows menu&#039;s in your screenio screens.&lt;br /&gt;
&lt;br /&gt;
*Wait Event: This event works in conjunction with the timeout setting you specify for your screen. This timeout value specifies the number of seconds before triggering a WAIT event. If you specify a WAIT event here, your event will be triggered if the keyboard is idle for that many seconds. If you do not write a WAIT event, the default ScreenIO Wait event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Record Locked: This event is triggered whenever a record is locked in a screenio screen. If you do not specify your own locked record event, the default ScreenIO Locked Record Event is triggered.&lt;br /&gt;
&lt;br /&gt;
*Exit Event: This event is triggered last, when the screen is being closed.&lt;br /&gt;
&lt;br /&gt;
===== Individual Control Events =====&lt;br /&gt;
&lt;br /&gt;
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.&lt;br /&gt;
&lt;br /&gt;
*Filter Event - In a Listview Control, the listviews event is the filter function that gets called to determine if the currently selected record should be added to the listview or not. Your filter function receives MAT F$ and MAT F for the screen, and if it returns true, (anything other then 0 or blank) then the record is included in the listview. If your filter function returns an HTML color code, then that HTML color is used to color that specific row of the listview. If there is no filter function, the listview displays every record in the data file.&lt;br /&gt;
**Listviews&lt;br /&gt;
  &lt;br /&gt;
*Validation - In a data Control, the data Control&#039;s event is the validation function that gets called to determine if the data is acceptable or not. If there is no Validation Function, then the data gets saved according to internal rules: All text data gets saved regardless of what it is, and numeric data is saved only if the user entered valid numeric data. The validation function receives the value the user is trying to save, and it can modify that data, and return true or false, to force the data to be saved or not. (However, you never can force saving string data in a numeric field, that will always be discarded by the ScreenIO Runtime Engine).&lt;br /&gt;
**TextBoxes&lt;br /&gt;
**CheckBoxes&lt;br /&gt;
**SearchBoxes&lt;br /&gt;
**Radio Buttons&lt;br /&gt;
**Filter Boxes&lt;br /&gt;
**Combo Boxes&lt;br /&gt;
  &lt;br /&gt;
*Click Events - Non-Data Controls have a &amp;quot;Click&amp;quot; event. This event is triggered whenever the user clicks on the control.&lt;br /&gt;
**Buttons&lt;br /&gt;
**Pictures&lt;br /&gt;
**Captions&lt;br /&gt;
&lt;br /&gt;
===== Purpose of Events =====&lt;br /&gt;
&lt;br /&gt;
By overriding various events with custom code, we can make your screen functions behave any way you want them to.&lt;br /&gt;
&lt;br /&gt;
=== Screens with two data files ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO Screen Functions are limited to one data file each. This means that each ScreenIO Screen function can only directly and automatically modify the MAIN data file for the screen. However, it is possible to modify additional related data files through the custom code added to the various screen events.&lt;br /&gt;
&lt;br /&gt;
It is possible to use ScreenIO to modify data sets of two data files with a parent/child relationship, by using four screens and tying them together, and setting special code in various events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
If you had a set of invoice files, with one invoice header file and another invoice detail file containing the line items of various invoices, and you wanted to maintain those files with ScreenIO, you would create four screens.&lt;br /&gt;
&lt;br /&gt;
The first screen would be a listview screen tied to the invoice header that would list all the invoices on record. (You could also set up a filter function limiting this display to invoices for a certain customer (passed in using ParentKey$) if you desired.) This screen would have buttons linking to the Add/Edit screen for invoice headers (the second screen described below).&lt;br /&gt;
&lt;br /&gt;
The second screen would be the Edit screen for the listview header. This screen would link (using Display Only) to the third screen (below) in its Enter Event. It would also have a button linking to the third screen (below) without the Display Only option, so that the user can click on this button and jump to the Listview displaying line items for the invoice.&lt;br /&gt;
&lt;br /&gt;
The third screen would be a listview for the invoice detail lines. This screen would have to have a filter function to limit its display to only lines on the currently selected invoice (which would be passed in using ParentKey$). You would link to this screen using &amp;quot;DisplayOnly&amp;quot; in the second screens &amp;quot;Enter Event&amp;quot;, so that when they are editing the invoice header records, they will also be able to view the line items on the listview. You would also have placed a button on Screen 2 linking to Screen 3 without Display Only (described above). The third screen, just like the first screen above, would have buttons linking to the Add/Edit screen for Invoice Detail items.&lt;br /&gt;
&lt;br /&gt;
The fourth screen would be a simple Add/Edit screen for the detail line items. In the initialize event for this screen, you would want to initialize the value in the detail file that ties it to the header file. In our example of invoices, we would initialize an invoice line item by specifying which invoice it appears on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This process allows you to quickly and easily create a set of four Screen Functions that preform complete FM operations on two linked data files with a parent/child relationship.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Animated Loading Icon ===&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
See [[#Working_with_the_ScreenIO_Loading_Icon|Working with the ScreenIO Loading Icon]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Save Money with Screen Functions ===&lt;br /&gt;
&lt;br /&gt;
==== Lower Development Costs ====&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;Screen Function&amp;quot;, depending on the complexity, represents about 4 - 8 hrs of traditional development time. Sage AX is selling all custom screens at a base price of $150. Custom processing code is occationally necessary to achieve particularly powerful effects, and it is available at a small additional charge. Most screen functions require little or no custom code, but more complex functionality is available. You can do just about anything with a screen.&lt;br /&gt;
&lt;br /&gt;
Because the screens are contained in Data files, they are easy to modify and easy to maintain.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO does the bulk of the work for you, the cost for custom processing code in your screens is lower then you might think.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Lower Maintenance Costs ====&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Runtime Library required to run your screens is free.&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Design engine used to create your screens is available for sale, for a one time unlimited-lisence fee. It will pay for itself after about 30 screens.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t need any special editor to edit the custom code that&#039;s already in your screen. That can be done by simply loading the screen helper library and modifying the code, the same way you would modify any BR program. However, if you make those sorts of changes yourself, you should send us a copy of your changes so that they can be included in any future modifications we make to that screen for you.&lt;br /&gt;
&lt;br /&gt;
Because ScreenIO uses FileIO to access all your data files, you never need to update your screens for file layout changes. This happens automatically because of the magic of the [[FileIO Library]]. The only thing you have to do is update your File Layouts.&lt;br /&gt;
&lt;br /&gt;
==== Estimated Price for your Screen Project ====&lt;br /&gt;
&lt;br /&gt;
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.&lt;br /&gt;
&lt;br /&gt;
Visit http://www.sageax.com/products/screenio-library/ for more details.&lt;br /&gt;
&lt;br /&gt;
== Screenio.ini ==&lt;br /&gt;
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.&lt;br /&gt;
&lt;br /&gt;
Inside this text file you want to place a small snipped of BR code setting the values for each of the setting variables listed below.&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the screenio.ini settings (which can also be found at the top of the screenio source code), along with their default values.&lt;br /&gt;
&lt;br /&gt;
  Setting_EnableLogging=0&lt;br /&gt;
  setting_FileIOPath$=&amp;quot;fileio&amp;quot;&lt;br /&gt;
  setting_ScreenIOPath$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClockPath$=&amp;quot;clocks\clock&amp;quot;&lt;br /&gt;
  setting_ImagePath$=&amp;quot;images&amp;quot;&lt;br /&gt;
  setting_ScreenFolder$=&amp;quot;screenio&amp;quot;&lt;br /&gt;
  setting_ClickToMove=1&lt;br /&gt;
  setting_PreviewListviews=1&lt;br /&gt;
  setting_RealtimeFilters=0&lt;br /&gt;
&lt;br /&gt;
If any of these are left out of your .ini file (or if your ini file is not found) then the defaults listed here are used instead.&lt;br /&gt;
&lt;br /&gt;
=== EnableLogging ===&lt;br /&gt;
This enables automatic logging via fileio&#039;s log function. See the FileIO documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== FileIOPath$ ===&lt;br /&gt;
This specifies the path to your copy of FileIO. &lt;br /&gt;
&lt;br /&gt;
  Note: Once you start using non-standard paths, it gets pretty tricky, so I would recommend sticking with the defaults. But if you have to change it, there are several other BR vendors who are successfully using it with nonstandard paths, by setting these settings properly.&lt;br /&gt;
&lt;br /&gt;
=== ScreenIOPath$ ===&lt;br /&gt;
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.&lt;br /&gt;
&lt;br /&gt;
=== ClockPath$ ===&lt;br /&gt;
This is the path to your clock files, used for the screenio loading animation.&lt;br /&gt;
&lt;br /&gt;
=== ImagePath$ ===&lt;br /&gt;
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.&lt;br /&gt;
&lt;br /&gt;
=== ScreenFolder$ ===&lt;br /&gt;
This is the folder to store the compiled screen helper libraries.&lt;br /&gt;
&lt;br /&gt;
=== ClickToMove ===&lt;br /&gt;
This allows you to turn off the automatic drawing of the movement grid, by setting it to 0. (You can always redraw the grid at any time by pressing the F6 key.) Also, you can turn it on for the duration of the current session by using the Windows Dropdown Menu &amp;quot;Tools&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== PreviewListviews ===&lt;br /&gt;
This allows you to turn off the automatic preview of the listview data, to save time during design. You can always change this setting later using the Tools menu.&lt;br /&gt;
&lt;br /&gt;
=== RealtimeFilters ===&lt;br /&gt;
This is the setting to use your listview filters when in design mode. You really should leave this setting off, because if there are any bugs in your filter functions, it&#039;ll make the designer crash, potentially causing you to loose the latest changes to the screen you&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
For that reason, this defaults to off, and I recommend you leave it off. If you want to test your filter functions, run your screen instead.&lt;br /&gt;
&lt;br /&gt;
== Making ScreenIO Screens ==&lt;br /&gt;
&lt;br /&gt;
It is also possible to purchase a ScreenIO Designer License, that entitles you to a full copy of the ScreenIO Designer, which you can use to make your own ScreenIO Screens. This part of the documentation deals with using the ScreenIO Screen Designer.&lt;br /&gt;
&lt;br /&gt;
=== The ScreenIO Designer (Overview and Reference) ===&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
The ScreenIO Designer is modeled after other modern visual program designers. However, it is written entirely in BR, and as such has a few limitations. We have done our best to work past the limitations of traditional BR programming by employing a clever combination of tricks and advanced BR syntax.&lt;br /&gt;
&lt;br /&gt;
At the top of the screen is the traditional Windows Menu. The left column of the Screen is made up of the Toolbar, which contains the Window Attributes, the Field List, and the ToolBox. At the bottom of the screen is the Debug window. The remaining space is the Editor window, where you can view and modify your screen in a graphical programming environment.&lt;br /&gt;
&lt;br /&gt;
==== Saving Your Screen ====&lt;br /&gt;
As in any development tool, it is very important to save your work as often as you think of it. There is no automatic save functionality built into ScreenIO.&lt;br /&gt;
&lt;br /&gt;
To save your screen, it has to at least have a Screen Name. Once you&#039;ve entered a Screen Name, you can save your screen using the Windows &amp;quot;File&amp;quot; dropdown menu (described below). Just click &amp;quot;File&amp;quot;, then select &amp;quot;Save&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Because of the nature of ScreenIO, often times you are typing in commands that get turned directly into BR code. As such it is impossible to guarantee that the ScreenIO designer will not ever encounter errors.&lt;br /&gt;
&lt;br /&gt;
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing &amp;quot;continue&amp;quot;. If you do, save your screen as soon as possible. Then use FileIO&#039;s datacrawler to fix the problem in the screen that led to the crash.&lt;br /&gt;
&lt;br /&gt;
===== Screen Backups for Multi User Environments =====&lt;br /&gt;
&lt;br /&gt;
In multiuser environments, even when source control is properly used, it is possible for one person to accidentally overwrite another persons screen. If that happens, do not fear. Look in the &amp;quot;backup&amp;quot; folder in the screenio copy on your local copy and you&#039;ll find a screenname.sio file that is a backup of your screen the last time you saved it.&lt;br /&gt;
&lt;br /&gt;
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.&lt;br /&gt;
&lt;br /&gt;
At any time, you can &amp;quot;import&amp;quot; one of these &amp;quot;.sio&amp;quot; files back into ScreenIO by using the &amp;quot;Import&amp;quot; option in the Windows Dropdown Menus. You&#039;ll want to check the name of the imported screen, and then save it using File -&amp;gt; Save, right away.&lt;br /&gt;
&lt;br /&gt;
==== Windows X ====&lt;br /&gt;
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.&lt;br /&gt;
&lt;br /&gt;
Clicking on the Windows X when running your screen will Cancel and Exit out of all screens that you may currently be in recursively until you reach the calling program. It is up to your calling program to then close whatever it was doing and exit.&lt;br /&gt;
&lt;br /&gt;
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.&lt;br /&gt;
==== ScreenIO Windows Menu ====&lt;br /&gt;
===== File =====&lt;br /&gt;
File Options&lt;br /&gt;
*New&lt;br /&gt;
Create a new screen.&lt;br /&gt;
*Load&lt;br /&gt;
Load a previously saved screen.&lt;br /&gt;
*Save and Compile&lt;br /&gt;
Save and Compile your screen.&lt;br /&gt;
*Compile&lt;br /&gt;
Compile your screen only. Use this if you&#039;ve changed some code but you haven&#039;t changed the screen itself.&lt;br /&gt;
*Save and Test&lt;br /&gt;
Save and Compile and Test your screen with one click.&lt;br /&gt;
*Export Screen&lt;br /&gt;
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.&lt;br /&gt;
&lt;br /&gt;
This will not save the custom screen functions. It is necessary to transfer any required custom screen functions by hand from the functions\ subfolder in your source ScreenIO implementation.&lt;br /&gt;
*Import Screen&lt;br /&gt;
Import a screen from a ScreenIO File (*.sio).&lt;br /&gt;
*Purge ScreenFlds File&lt;br /&gt;
Because of the way ScreenIO Stores the screen information, the screenflds file tends to grow and grow. Run this menu option to purge all deleted records from this file and free up all the unnecessary space.&lt;br /&gt;
*Recompile All Screens&lt;br /&gt;
This menu option automatically recompiles all your ScreenIO Autogenerated Helper Libraries. This is useful if you made a change to a Custom Screen Function that is in use by more then one screen, and you want to apply the change everywhere in your implementation at once.&lt;br /&gt;
*FileIO&lt;br /&gt;
This launches a copy of FileIO running in its own window, so you can interact with your data files if you need to, and so you can access the FileIO Template Code Generation Wizard.&lt;br /&gt;
*New Window&lt;br /&gt;
This launches another copy of ScreenIO running in its own window so that you can edit two screens at the same time, or take advantage of a multiple monitor environment.&lt;br /&gt;
*BR Console&lt;br /&gt;
This loads a new copy of BR by itself. (Note that it uses your standard brconfig.sys file so if you have any Startup Program instructions there, your startup program will still run.&lt;br /&gt;
*Explore Local Folder&lt;br /&gt;
This loads the current directory in Windows Explorer, so that you can interact with the file system, or make new file layouts, or whatever you need to do.&lt;br /&gt;
*Quit&lt;br /&gt;
Exits ScreenIO and closes BR.&lt;br /&gt;
===== Options =====&lt;br /&gt;
Performance Options&lt;br /&gt;
*Click to Move&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
This setting enables/disables the grid of blue dots that allows you to quickly move your controls around the screen by just clicking on the destination. On some computers, or some network settings, the click-to-move dots can slow down performance noticably. If this happens, disable the dots by using this menu setting, and move the controls around using the keyboard instead of the click to move dots. (Use the Arrow Keys).&lt;br /&gt;
&lt;br /&gt;
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.&lt;br /&gt;
&lt;br /&gt;
*Preview Listviews&lt;br /&gt;
Default: On&lt;br /&gt;
&lt;br /&gt;
ScreenIO attempts to provide the developer with a WYSIWYG environment. To that end, it renders your screen as much as it possibly can at design time.&lt;br /&gt;
&lt;br /&gt;
If you make a Listview Screen for a Data File that has records in it, the ScreenIO Designer will do the best it can to populate that listview even while you are designing the listview.&lt;br /&gt;
&lt;br /&gt;
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the &amp;quot;Preview Listviews&amp;quot; setting off.&lt;br /&gt;
*Real Time Filters&lt;br /&gt;
Default: Off&lt;br /&gt;
&lt;br /&gt;
If your ScreenIO listview has a custom filter function assigned to it, you can enable the use of the filter function during the WYSIWYG Preview Listview rendering.&lt;br /&gt;
&lt;br /&gt;
Depending on the resources of your computer, this setting can have a serious impact on performance.&lt;br /&gt;
&lt;br /&gt;
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.&lt;br /&gt;
===== Tools =====&lt;br /&gt;
Developer tools to help you with development in ScreenIO.&lt;br /&gt;
*Power Search&lt;br /&gt;
This is a powerful search tool, inspired and requested by Susan Smith. It searches all your custom functions, your screens themselves, and any additional folders of both compiled and noncompiled BR programs or even proc files, for any mention of the specified search string anywhere in your system.&lt;br /&gt;
&lt;br /&gt;
Powersearch now also supports typing in any field from your database, in the format of prefix_subscriptname. For example, searching for cu_name in my copy of ScreenIO would return every piece of code and every screen element that uses the customer name field, and also the customer file layout itself.&lt;br /&gt;
&lt;br /&gt;
*Code Explore&lt;br /&gt;
Opens a list showing all the custom functions that are used in your current screen. This is useful for getting an idea of exactly what the current screen contains/is built out of.&lt;br /&gt;
*Generate Screen&lt;br /&gt;
This wizard asks for a data file, then queries you for which fields to use, and generates a Listview, an Add/Edit, and/or a Combo Listview/Add/Edit screen with almost everything in place and done for you. You use the Generate Screen Wizard to get you most of the way there, and then all you have to do is modify the control positions, add validation functions if necessary, and test your screen.&lt;br /&gt;
*Generate Code&lt;br /&gt;
Generates the BR code to create a standard BR input fields statement to do your current screens input. Note that this does not create a ScreenIO Screen as BR code because it doesn&#039;t include your custom function processes.&lt;br /&gt;
&lt;br /&gt;
This feature is primarily useful for when you have to design a piece of code the old way, and just want to use ScreenIO to help you get the appearance right, and then have ScreenIO Generate your field specs for the BR program you&#039;re writing.&lt;br /&gt;
*Orphaned Functions&lt;br /&gt;
Displays a list of all functions in your functions folder that are no longer in use by any screens.&lt;br /&gt;
&lt;br /&gt;
===== Add Control =====&lt;br /&gt;
The add control menu gives you keyboard access for adding any control you want to your screen. &lt;br /&gt;
&lt;br /&gt;
*Add Field&lt;br /&gt;
This places the cursor in the Fields Listview where you can select fields from your data file and with the arrows and add them to your screen by pressing &amp;quot;Enter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Add Exit Buttons&lt;br /&gt;
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds &amp;quot;Select&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. If its an Add/Edit screen, then it gives you &amp;quot;Save&amp;quot; and &amp;quot;Cancel&amp;quot; buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls. &lt;br /&gt;
&lt;br /&gt;
*Add Add/Edit Buttons&lt;br /&gt;
This asks you for the target Edit screen and adds buttons to a Listview screen that tie to the selected target Edit screen, for Adding new records or Editing the current record.&lt;br /&gt;
&lt;br /&gt;
You can accomplish the same thing by adding individual buttons and customizing their captions, positioning, and click event functions, but this does it all for you in one click.&lt;br /&gt;
*Add Textbox&lt;br /&gt;
Adds a Textbox. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Caption&lt;br /&gt;
Adds a Caption. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Checkbox&lt;br /&gt;
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Combo Box&lt;br /&gt;
Adds an empty Combo Box to your screen. You&#039;ll need to specify a combo &amp;quot;Populate&amp;quot; function to populate the data in your combo box. This doubles as a validation function so you can also validate and respond to the user changing the selection in the same function. Other then the populate function, combo boxes are just like regular input fields.&lt;br /&gt;
*Add Listview&lt;br /&gt;
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Searchbox&lt;br /&gt;
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Filterbox (4.3+)&lt;br /&gt;
Adds a BR 4.3 Filter Box to your current screen. These work like Search Boxes, except they narrow the results in the listview in real time as the user types in the filter box.&lt;br /&gt;
*Add Button&lt;br /&gt;
Adds a Button. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Picture&lt;br /&gt;
Adds a Picture. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
*Add Frame&lt;br /&gt;
Adds a frame, which is actually a child window to your screen. The frame can have a border or not, and it can have a background image or not, which allows you to place fields on top of a background image.&lt;br /&gt;
&lt;br /&gt;
If you move the frame, all the controls in the frame move too. Therefore I recommend building your frames first and then placing the fields in them.&lt;br /&gt;
&lt;br /&gt;
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.&lt;br /&gt;
*Add Screen&lt;br /&gt;
This adds a ScreenIO Screen as a child screen on the current screen. The child screen is loaded and displayed when the current screen is run. If the user clicks on the child screen, then screenio calls the child screen for processing, and when its done, returns to the parent screen and updates properly.&lt;br /&gt;
&lt;br /&gt;
If they&#039;re inside the child screen and click on a field in the parent screen, the child screen closes automatically and control is returned to the parent screen and whatever they click on is enacted.&lt;br /&gt;
&lt;br /&gt;
*Skip A Space&lt;br /&gt;
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.&lt;br /&gt;
&lt;br /&gt;
===== Screen =====&lt;br /&gt;
Screen Options&lt;br /&gt;
*Adjust Screen Size&lt;br /&gt;
Automatically resizes your screen to just large enough to fit all your controls on it.&lt;br /&gt;
*Move Controls&lt;br /&gt;
This puts ScreenIO into Control Movement Mode&lt;br /&gt;
*Draw Movement Grid&lt;br /&gt;
This draws the Movement Grid to aid in moving your controls. This way you can disable the movement grid by setting the option in your ini file, and draw it only when needed. The F6 key is a shortcut to draw the movement grid.&lt;br /&gt;
*Visit Checklist&lt;br /&gt;
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.&lt;br /&gt;
*Set FG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Foreground Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set BG Color&lt;br /&gt;
This brings up the color selector, allowing you to select the Background Color for your screen. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Select File Layout&lt;br /&gt;
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.&lt;br /&gt;
*Set Events&lt;br /&gt;
This menu option does the same thing that clicking on the &amp;quot;Set Events&amp;quot; button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.&lt;br /&gt;
*Set Tab Order&lt;br /&gt;
This menu option allows you to set the tab order by clicking on all of your screen controls in the order that you want the tab order to go. This function is also availble from the &amp;quot;Set Tab Order&amp;quot; button in the Window Attributes corner of the ScreenIO Designer.&lt;br /&gt;
*Configure Debug&lt;br /&gt;
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.&lt;br /&gt;
*Configure Additional Info&lt;br /&gt;
This opens a window to configure additional screen level options that didn&#039;t fit on the main ScreenIO screen Attributes window.&lt;br /&gt;
*Test Screen&lt;br /&gt;
This option fires up a second copy of BR to test your screen. All screenIO screens can be exited by clicking on the Windows X. Your screen runs in a completely separate instance of BR, so you don&#039;t have to worry about the test of the screen screwing up whats going on in your editor.&lt;br /&gt;
&lt;br /&gt;
Its important to remember to save your screen before testing it. Otherwise, you will see the previous version of the screen when you test it.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will attempt to use the same BR executable and brconfig.sys file that you loaded screenio with, so make sure its the one you want to use for your application.&lt;br /&gt;
&lt;br /&gt;
===== Help =====&lt;br /&gt;
Help Menu&lt;br /&gt;
*Documentation&lt;br /&gt;
This menu option links to this wiki document.&lt;br /&gt;
*About&lt;br /&gt;
Opens the ScreenIO About screen.&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Designer Modes ====&lt;br /&gt;
The ScreenIO Designer has several different modes that it operates in. For the most part this is designed to be seamless to the programmer but it may help to understand whats going on behind the scenes.&lt;br /&gt;
&lt;br /&gt;
BR has a major interface limitation, in that only one child window is able to be input from at a given time. The ScreenIO designer attempts to hide this problem by using different modes. The modes are as follows:&lt;br /&gt;
&lt;br /&gt;
  let Inputattributesmode=1&lt;br /&gt;
  let Inputfieldlistmode=2&lt;br /&gt;
  let Inputeditormode=3&lt;br /&gt;
  let Inputeditormovemode=4&lt;br /&gt;
  let Inputdebugmode=5&lt;br /&gt;
  let Quitmode=6&lt;br /&gt;
  let Selectcolormode=7&lt;br /&gt;
  let Selectfilelaymode=8&lt;br /&gt;
  let Inputlistviewmode=9&lt;br /&gt;
  let Selecteventsmode=10&lt;br /&gt;
  let Settabordermode=11&lt;br /&gt;
  let Configuredebugmode=12&lt;br /&gt;
&lt;br /&gt;
Input Attributes Mode is when the cursor is in the upper left corner of the screen, inputting the attributes for the whole screen. If you&#039;re in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode.&lt;br /&gt;
Input FieldsList Mode is when the cursor is in the fields listview, and you&#039;re selecting fields to add to the screen.&lt;br /&gt;
Input Editor Mode is when the cursor is in the attributes for a single field.&lt;br /&gt;
Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots.&lt;br /&gt;
Input Debug Mode is when the Todo List debug at the bottom of the screen is active.&lt;br /&gt;
Quit Mode is used to tell the designer to exit.&lt;br /&gt;
Select Color Mode is the current mode whenever you&#039;re selecting a color for something.&lt;br /&gt;
Select FileLay Mode is used to select the file layout for your screen.&lt;br /&gt;
Input Listview Mode is the mode for entering the information for listview columns.&lt;br /&gt;
Select Events mode is the mode you&#039;re in when you&#039;re selecting screen level events.&lt;br /&gt;
Set Tab Order Mode is the mode for setting the tab order.&lt;br /&gt;
Configure Debug Mode is the mode for configuring the debug window.&lt;br /&gt;
&lt;br /&gt;
You can generally tell what mode you&#039;re in because that part of the screen will light up yellow.&lt;br /&gt;
==== Toolbar ====&lt;br /&gt;
The Toolbar Window is along the left side of the screen. It is made up of the Window Attributes window, the Fields List, and the Toolbox.&lt;br /&gt;
===== Window Attributes =====&lt;br /&gt;
The Window Attributes window contains information about all Screen level Attributes.&lt;br /&gt;
====== Window Name ======&lt;br /&gt;
This is the unique 8 digit Window Name. It is used as the unique key in the ScreenIO data file. It is the name you use to load your screen from code, and the name you use when you load your screen from the ScreenIO Designer File-&amp;gt;Load menu.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This is the Caption in the Windows Title Bar when you run your application. If the Window you are creating has a border specified, then this is also the caption that appears in the border of that Child Window&lt;br /&gt;
====== Rows ======&lt;br /&gt;
The number of Rows your window takes up. You can change this any time, and your screen will adjust on the fly. This makes it easy to design your screens and then adjust the size of them when you already know what they will look like.&lt;br /&gt;
&lt;br /&gt;
If you make your screen too small and not all the controls fit on it, the ones that are outside the border of the window will not be rendered, and a Debug Message will appear in the Debug Window. Simply make your screen large enough for all the controls to appear and move the offending controls away from the edge, and then resize your screen again to the size you want it to be.&lt;br /&gt;
====== Cols ======&lt;br /&gt;
The number of Columns your window takes up. See Rows (above) for more information.&lt;br /&gt;
====== Attributes ======&lt;br /&gt;
This Attributes Screen is used when opening your window. You can place any valid BR Window Attribute statement here. For example, to make your screen have a border around it, type &amp;quot;BORDER=S&amp;quot; in the Attributes setting for the window.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
Type the path and filename of a picture file, and it will be used as the background image for your Screen.&lt;br /&gt;
====== Read Key ======&lt;br /&gt;
Specify the key to use when reading the file. The default is the first key specified in the layout for Add/Edit screens, and Sequential Read for Listview Screens.&lt;br /&gt;
====== Return Key ======&lt;br /&gt;
Specify the key to use when calculating the return value. The default is the first key specified in the layout.&lt;br /&gt;
====== Input Attr ======&lt;br /&gt;
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.&lt;br /&gt;
====== Wait Time ======&lt;br /&gt;
Specify the time to wait in seconds of keyboard inactivity before triggering a WAIT event. If you have no WAIT event specified, then ScreenIO will trigger the default ScreenIO WAIT event.&lt;br /&gt;
====== FG Color ======&lt;br /&gt;
This is the default Foreground Color when adding new controls to the screen.&lt;br /&gt;
====== BG Color ======&lt;br /&gt;
This is the background color for the screen.&lt;br /&gt;
====== File Layout ======&lt;br /&gt;
Click this button to select the file layout that your screen applies to.&lt;br /&gt;
====== Set Form Events ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Form Events. It opens a window where you can view and configure the ScreenIO Custom Helper Functions that get triggered for each of your Form (Screen) level Events.&lt;br /&gt;
====== Set Tab Order ======&lt;br /&gt;
This button is a shortcut to the Windows Menu: Screen-&amp;gt;Set Tab Order. It allows you to change the tab order of your screen by clicking on your screen controls in the order that you would like the tab order to become.&lt;br /&gt;
===== Field List =====&lt;br /&gt;
This listview shows all the fields in the currently selected File Layout.&lt;br /&gt;
&lt;br /&gt;
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in &amp;quot;Input Fields List Mode&amp;quot; because the background for the Listview will turn Yellow. When you are in &amp;quot;Input Fields List Mode,&amp;quot; you can navigate the listview with the mouse or arrow keys. Pressing Enter or Double Clicking on an item will add it to your new screen.&lt;br /&gt;
===== Toolbox =====&lt;br /&gt;
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.&lt;br /&gt;
====== Field ======&lt;br /&gt;
This button adds the currently selected field from the Fields List to your new screen. This is the same as double clicking on a listview item or pressing enter while in Input Fields List Mode (while the Fields List is yellow). If you are not currently selecting a field from the Fields Listview, then clicking on this button does nothing.&lt;br /&gt;
&lt;br /&gt;
The currently selected field is added as a Textbox that is automatically tied back to your data file. To the left of this new textbox is a caption containing the description from the File Layout for this field. Both can be customized to your hearts content, and positioned any place you want on the screen.&lt;br /&gt;
====== TextBox ======&lt;br /&gt;
This button adds an empty Textbox Control to your new screen. This textbox control can then be configured and tied to a field from the data file, or left as a Screen field that can be accessed and modified by your custom ScreenIO Helper Functions.&lt;br /&gt;
====== MultiLine Textbox ======&lt;br /&gt;
BR Supports Multi-Line Textboxes via a little-known programming trick that dates back to the days before graphical controls. It is possible to use this technique to make multiline textboxes in BR, and ScreenIO makes the process easy for you. The only down side to BR multi-line text boxes is that you can only make a multiline text box that goes all the way to both the left and right side of the window.&lt;br /&gt;
&lt;br /&gt;
To make a MultiLine textbox in ScreenIO, simply add a regular textbox to the screen and then press the PgDn key while in movement mode. It will stretch horizontally to fill the screen, and grow to become a multiline textbox.&lt;br /&gt;
====== Caption ======&lt;br /&gt;
This button adds an empty Caption Control to your new screen. This caption can be configured and the Text to display can be specified. Or, you can tie it to a field in the data file, or leave it as a Screen field that can be accessed and modified by your Custom ScreenIO Helper Functions&lt;br /&gt;
====== CheckBox ======&lt;br /&gt;
This button adds an empty Checkbox Control to your new screen. This Checkbox can be configured and its caption can be specified. It can also be tied to a data file, or left as a Screen field that you can access and modify.&lt;br /&gt;
&lt;br /&gt;
You can tie your checkbox to a field in your data file by specifying a TrueValue and a FalseValue in addition to a FieldName for a field from the file. If the checkbox is checked, the truevalue you specify will be saved in the file. If its not, the falsevalue will be saved in the file.&lt;br /&gt;
&lt;br /&gt;
====== Radio Button ======&lt;br /&gt;
To add a Radio Button, start by adding a Checkbox to your screen. Then convert the Check box into a Radio Button using the following procedure.&lt;br /&gt;
&lt;br /&gt;
You can turn your checkboxes into radio buttons very easily. Simply add a group number (1,2,3,etc) in the attribute field and your checkbox will be converted to a radio button as ScreenIO builds the screen.&lt;br /&gt;
&lt;br /&gt;
You oftentimes will want to tie a group of Radio Buttons to a single field in the data file. In that event, specify the same field name for every radio button, and specify the True Value that you want associated with each Radio button in the group. For falsehood values for all the controls in the group, specify a value of &amp;quot;~ignore~&amp;quot;. This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.&lt;br /&gt;
&lt;br /&gt;
====== Combo Box ======&lt;br /&gt;
To add a combo box, simply click the Add Combo Box button. Then you can tie it to a field in your data file (if you like) or give it a name so it becomes an S$ field.&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.&lt;br /&gt;
&lt;br /&gt;
This is a special function that accepts a parameter called mat ReturnData$. You size mat ReturnData$ to the number of elements you want in your combo box, and set the elements, and you&#039;re done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.&lt;br /&gt;
&lt;br /&gt;
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you&#039;ll want to return true in order to allow the user to change the combo box selection. You can also perform validations and return true only when they change it to something valid.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 def fnPopulateApproval&lt;br /&gt;
     mat returndata$(3)&lt;br /&gt;
     let returndata$(1)=&amp;quot;None&amp;quot;&lt;br /&gt;
     let returndata$(2)=&amp;quot;Approve&amp;quot;&lt;br /&gt;
     let returndata$(3)=&amp;quot;Hold&amp;quot;&lt;br /&gt;
     let fnPopulateApproval=1&lt;br /&gt;
 fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview ======&lt;br /&gt;
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter &amp;quot;Edit Listview Columns&amp;quot; mode, then you can add or remove columns from the listview. If you are currently in Edit Listview Columns mode, then you can click on the Fields List to automatically add listview columns from your datafile directly.&lt;br /&gt;
====== Search Box ======&lt;br /&gt;
This button adds a Search Box and ties it automatically to a listview if one is found. You can also tie the Search Box to a Listview later from its control attributes window.&lt;br /&gt;
====== Filter Box (4.3+) ======&lt;br /&gt;
This button adds a BR 4.3 Filter Box to your screen and ties it to the current control. This filter box is just like a list box, except that as the user types, the list is shortened in realtime to display only matching elements.&lt;br /&gt;
&lt;br /&gt;
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.&lt;br /&gt;
====== Button ======&lt;br /&gt;
This button adds a Button to your new screen. You can specify a Click Event Handler, some custom BR code that gets triggered whenever the button is clicked on.&lt;br /&gt;
====== Picture ======&lt;br /&gt;
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.&lt;br /&gt;
====== Frame ======&lt;br /&gt;
This button adds a frame to your screen. Frames are built off of BR Child Windows, and you can place controls on them. They can optionally have a border, and/or a background image, allowing you to place fields on top of a picture.&lt;br /&gt;
&lt;br /&gt;
It is recommended to place your frames first and then place controls in the frames. This is because, as you move the frames around the screen, they move any controls around with them. So if you place the controls first and try to move the frame on top of them, you&#039;ll collect all the controls on top of each other along the leading edge of the frame.&lt;br /&gt;
====== Screen ======&lt;br /&gt;
This button adds a child screen to your screen. This screen is displayed when the screen is drawn, and if the user clicks on it, its automatically called and run for you.&lt;br /&gt;
&lt;br /&gt;
If the user then clicks on another control in the main screen, the child screen will be exited automatically (defaults to use AskSaveAndQuit if there&#039;s no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.&lt;br /&gt;
====== Skip a Space ======&lt;br /&gt;
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.&lt;br /&gt;
&lt;br /&gt;
==== Editor ====&lt;br /&gt;
The Editor Window contains your new screen.&lt;br /&gt;
&lt;br /&gt;
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.&lt;br /&gt;
==== Debug ====&lt;br /&gt;
The Debug window lists potential warnings and errors discovered by our Screen validation routine.&lt;br /&gt;
&lt;br /&gt;
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don&#039;t really make sense, even though they aren&#039;t really going to cause an error.&lt;br /&gt;
&lt;br /&gt;
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.&lt;br /&gt;
&lt;br /&gt;
If you double click on a message, the ScreenIO validation routines will do their best to take you to the location of the error so you can find it and fix it more easily.&lt;br /&gt;
&lt;br /&gt;
=== Using the ScreenIO Designer ===&lt;br /&gt;
Now that we have gone over the various elements that make up the ScreenIO Design Library, lets take a closer look at the process of making a Screen.&lt;br /&gt;
&lt;br /&gt;
==== Create a New Screen ====&lt;br /&gt;
The first thing that every screen needs is a Screen Name.&lt;br /&gt;
&lt;br /&gt;
Fire up the ScreenIO Designer. You will notice a few messages in the Debug window, right off the bat. One of these is an error message, that says &amp;quot;Window Name cannot be blank.&amp;quot; (The message may appear white on a blue background instead of Red on a White background. This is because of the current row selection bar, which is White on Blue.)&lt;br /&gt;
&lt;br /&gt;
The Window Name is the primary unique key for the ScreenIO Screens file, and every screen needs one. You use the Screen Name when invoking your screen, and when loading it from the File-&amp;gt;Load menu.&lt;br /&gt;
&lt;br /&gt;
Enter a name for your new screen.&lt;br /&gt;
&lt;br /&gt;
The next step is to Select the File Layout for your screen.&lt;br /&gt;
&lt;br /&gt;
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO&#039;s ability to automatically modify data files that have been defined within the [[FileIO Library]] system.&lt;br /&gt;
&lt;br /&gt;
In order to use ScreenIO to create screens that dynamically interact with your data files, it is first necessary to define your data files with FileIO style file layouts. If you have not done so, do so now. For more information on the [[FileIO Library]], visit the [[FileIO Library]]s page on this wiki.&lt;br /&gt;
&lt;br /&gt;
Click the button to the right of the text &amp;quot;File Layout:&amp;quot;. Select the file layout for the file you plan to interact with using this screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Designer_-_Add_Edit_Screen_-_Field_Selection_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Add Fields to your new Screen ====&lt;br /&gt;
As soon as you select your file layout, the Field List listview should populate with all of the fields in the selected data file. At this point, you can add these fields to your Screen, by selecting them from the Field List listview and pressing the &amp;quot;Add Field&amp;quot; button (or pressing &amp;quot;Enter&amp;quot; from the Field List listview).&lt;br /&gt;
&lt;br /&gt;
The fields you add will appear in the top left corner of your screen. You can go ahead and add all the fields you want in a row. They will all go on top of each other, and the Debug Window will change to reflect that many of your controls cannot be drawn because they are on top of each other.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to create a Listview Screen instead, you can do that by adding a Blank Listview control to your screen. Then, follow the instructions below to position your listview where you want it. When your listview is in the position and size you&#039;d like it, press Enter twice, to go to &amp;quot;Edit Listview Columns Mode&amp;quot;. Click the &amp;quot;Delete Column&amp;quot; button once to delete the Empty Listview Column that appears by default, and then click on the Field List to Jump to the Field List listview. From the field list, you can then add columns directly from your data file to your listview, by selecting them and pressing Enter.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Movement_Mode.jpg|thumb|800px]]&lt;br /&gt;
==== Position the fields on your new Screen ====&lt;br /&gt;
When you have finished adding your fields, click on one of your controls in the Editor window. A grid of small blue dots should appear, and your selected control will appear in Yellow, indicating that you are in Movement Mode.&lt;br /&gt;
&lt;br /&gt;
While you are in Movement Mode, ScreenIO will group your captions with your textboxes for any controls that were added together. If you move the textbox control, the caption associated with it will move automatically. This is regardless of weather or not the caption is part of a control group.&lt;br /&gt;
&lt;br /&gt;
This piece of magic is accomplished via the [[#Caption Field|Caption Field]] poperty.&lt;br /&gt;
&lt;br /&gt;
===== Keyboard Control Movement =====&lt;br /&gt;
In Movement Mode, you can position your control using the Arrow Keys. The Backspace Key makes your control narrower, while the Space Key makes your control Wider. PgUp and PgDn make your 2D control Taller or Shorter. Enter toggles between Movement Mode, and Control Attributes Mode. For more information, see the chapter on [[#Screen_Control_Movement_Mode|Screen Control Movement Mode Keyboard Reference]].&lt;br /&gt;
&lt;br /&gt;
===== Click to Move Control Movement =====&lt;br /&gt;
While BR does not support true Drag and Drop, you can approximate the functionality of Drag and Drop in BR. This is what the ScreenIO Click to Move feature is all about.&lt;br /&gt;
&lt;br /&gt;
While you are positioning your controls around the screen, the currently selected control is highlited in Yellow, and the BR Print Statement for the control is displayed in the text of the control.&lt;br /&gt;
&lt;br /&gt;
If you click on one of the blue dots, your control will jump to that location. You can use this feature to quickly place your controls on the screen.&lt;br /&gt;
&lt;br /&gt;
First, click on the control that you want to move. It will highlite in Yellow. Then click on the blue dot where you want to move it to. It will move there. If there is a control group selected, then all the controls in the selected group will be moved relative to how the main control moved.&lt;br /&gt;
&lt;br /&gt;
When you move your controls around, select the Text Box field and move that first. The Caption field will automatically move with you, following the Text Box around the screen. This may be confusing at first, but this feature is designed to save you time in the long run.&lt;br /&gt;
&lt;br /&gt;
Move all of your new controls around until your screen looks nice. You can also resize your screen at any time by changing the values in the Window Attributes window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;However, the Click to Move feature can significantly slow down the ScreenIO Designer on computers with limited resources. If you prefer to turn it off, you can do so from the Options menu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window.jpg|thumb|800px]]&lt;br /&gt;
&lt;br /&gt;
==== Control Attributes Window ====&lt;br /&gt;
&lt;br /&gt;
When you have your screen looking the way you want it, it is time to begin modifying the attributes of your individual controls. Click on the control that you want to view the attributes for to select it. It will highlight in Yellow. Click it a second time (or press the Enter key) and a little window will open up showing all the attributes for the given control.&lt;br /&gt;
&lt;br /&gt;
The control attributes window shows all the customizable attributes for each of your screen objects. Each object type has its own set of attributes and events.&lt;br /&gt;
&lt;br /&gt;
[[image:ScreenIO_Designer_-_Control_Attributes_Window_-_Closeup.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of all the available Control Attributes and what they do:&lt;br /&gt;
===== Control Name =====&lt;br /&gt;
This is the name for the control. Your controls do not require a name. However, if your control is not tied to a field, but you give it a name, then ScreenIO automatically reserves a place for that control in Mat S$. You can modify the value of that control within your Custom Screen Functions by using its control name.&lt;br /&gt;
&lt;br /&gt;
You can also use the control name to identify controls from within your event functions. If the control is called MyControl, then you can access its Background Color by looking at BgColor$(ctl_MyControl).&lt;br /&gt;
&lt;br /&gt;
===== Field =====&lt;br /&gt;
This is the field the control is tied to in your data file. When the user enters the screen, the record is read (or added) and the information from this field is displayed in the control. When the user finishes modifying the code and presses the Save button, the information is automatically saved back into the data file for you. Validation is provided for in the Validation Function (explained below).&lt;br /&gt;
===== Caption =====&lt;br /&gt;
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).&lt;br /&gt;
===== Caption Field =====&lt;br /&gt;
This is the Control Name of the field that is tied to this field for movement purposes.&lt;br /&gt;
&lt;br /&gt;
Any time you use the Movement Mode to move a control around, if it has a Caption Field specified, then the control referenced in the caption field is moved automatically for you. This helps keep the caption next to the text box it applies to.&lt;br /&gt;
&lt;br /&gt;
===== Spec Width =====&lt;br /&gt;
This is the Internal Width of the data allowed in the control. This is not to be confused with the physical display width of the control. You modify the Display Width of a control by pressing &amp;quot;Space&amp;quot; or &amp;quot;BackSpace&amp;quot; when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.&lt;br /&gt;
===== Sort Column =====&lt;br /&gt;
The Sort Column attribute applies to ListViews only, and specifies which column the listview is sorted on when the program is first loaded. If you are using a search box with your listview, then it is highly reccomended that you specify a Sort Column along with it. Otherwise, your Search Box will not be usable until the user manually sorts the Listview by clicking on the column headings.&lt;br /&gt;
&lt;br /&gt;
If you want your listview to sort in Descending Order, then specify a negative number. If you want it to sort in ascending order then specify a positive number here.&lt;br /&gt;
&lt;br /&gt;
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.&lt;br /&gt;
===== Multiselect =====&lt;br /&gt;
This check box indicates weather you want to allow multi-selection in your listview or not. If you do enable multiselection, then use mat SelectedKeys$ or mat SelectedRecords in your custom functions to see which records the user has selected from your data file.&lt;br /&gt;
===== Truth Value =====&lt;br /&gt;
The Truth Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Truth Value specifies the value that represents True in the data file for this Check Box.&lt;br /&gt;
===== Falsehood Value =====&lt;br /&gt;
The Falsehood Value attribute applies to Checkboxes only, and is used to translate a checked/unchecked value into the true and false values for your data files.&lt;br /&gt;
&lt;br /&gt;
Everybody uses something slightly different in their data files to represent True and False. Some people use &amp;quot;Y&amp;quot; or &amp;quot;N&amp;quot;. Some people use &amp;quot;T&amp;quot; and &amp;quot;F&amp;quot;. Some people use 1 and 0 to represent True and False in their data files. The Falsehood Value specifies the value that represents False in the data file for this Check Box.&lt;br /&gt;
&lt;br /&gt;
====== ~Ignore~ (Radio Buttons) ======&lt;br /&gt;
If you are using Radio Buttons, you&#039;ll often want to tie several buttons to a single data file. To do this, you will specify the value that you want each option to write to the disk using the Truth Value, and for the false value you want to specify &amp;quot;~ignore~&amp;quot;. This will tell ScreenIO to ignore the false value, and when the user selected a new radio button, the truth value for the radio button they selected will be used as opposed to the false value for the radio button that they unselected.&lt;br /&gt;
&lt;br /&gt;
===== Function =====&lt;br /&gt;
The Function attribute specifies the Click event for your Button or Picture control. Press the Edit button to select from your existing Custom Screen Functions, or create a new one. See the Custom Screen Function section of this document (below) for more information about Custom Screen Functions.&lt;br /&gt;
&lt;br /&gt;
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.&lt;br /&gt;
===== Validation =====&lt;br /&gt;
The Validation attribute identifies the Custom Screen function that gets triggered whenever the data in the control is changed. You can use this event to ensure that only valid data gets saved in the database. If your validation event returns false (0) or a null string then the data the user entered is thrown out, and the previous value is replaced in the control.&lt;br /&gt;
===== Filter =====&lt;br /&gt;
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.&lt;br /&gt;
&lt;br /&gt;
Your filter function gets triggered for Each Row in the data file, before it is added to the listview. You can use the Filter event to include/exclude certian records from the listview. You can also modify the data displayed in the listview before it goes to the screen.&lt;br /&gt;
===== Conversion =====&lt;br /&gt;
The conversion field specifies to ScreenIO how to treat numeric data. You can specify any valid BR field spec, or FMT, PIC or DATE here. You may also specify your own conversion function to be used when unpacking the data from the disk.&lt;br /&gt;
&lt;br /&gt;
====== Special ScreenIO Date processing ======&lt;br /&gt;
If you use DATE then it will convert the value from a julian date into the date format you specify, and when its writing it back to the disk, it will convert it back to the julian date value before saving it to the disk.&lt;br /&gt;
&lt;br /&gt;
This is a very robust way to handle dates in your system. This supports the user entering in any format they find natural, and if they leave off the year, current year is assumed.&lt;br /&gt;
&lt;br /&gt;
If the first character is a + or a -, then the number they entered is assumed to be a relative date, so they can also type +5 to say &amp;quot;five days from now&amp;quot;, or +2w to say &amp;quot;14 days from now&amp;quot;, or +3m or -1y, etc.&lt;br /&gt;
&lt;br /&gt;
===== Picture File =====&lt;br /&gt;
This specifies the path and filename of the picture file to use for the picture control. All the image types supported by BR are supported here.&lt;br /&gt;
===== Foreground Color (Header FG Color) =====&lt;br /&gt;
This is the foreground color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Background Color (Header BG Color) =====&lt;br /&gt;
This is the background color of the control. If you intend to use Attribute Substitute statements to color your controls, then you need to leave the Foreground Color and Background Colors blank, as these values will override the colors specified in your Attribute Substitute Statements.&lt;br /&gt;
===== Justification Spec =====&lt;br /&gt;
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default &amp;quot;C&amp;quot; is Left Justify. You can specify:&lt;br /&gt;
&lt;br /&gt;
*C - Left Justify&lt;br /&gt;
*CC - Center Justify&lt;br /&gt;
*CR - Right Justify&lt;br /&gt;
*CU - Force Uppercase&lt;br /&gt;
*CL - Force Lowercase&lt;br /&gt;
===== Set Listview =====&lt;br /&gt;
The Set Listview attribute applies to Search Boxes only, and specifies the Listview that the Search Box is tied to. When the user types something in the Search Box, the Listview will automatically jump to the record they are typing, based on which column the listview is sorted on.&lt;br /&gt;
&lt;br /&gt;
If you have a Search Box, but no Sort column is specified in your listview, then an Error message is displayed in your Debug Window.&lt;br /&gt;
&lt;br /&gt;
When you click the &amp;quot;Set Listview&amp;quot; button, the search box is automatically tied to the listview on the screen. (At this time ScreenIO does not support more then one listview on a logical screen at a given time.) The Spec Width for the Search Box is automatically updated to match the largest column in the listview.&lt;br /&gt;
&lt;br /&gt;
If you added your listview before you added your search box, then the Search Box is already tied to your Listview by default. When your search box is tied to a listview, you will see the internal name of the listview (usually &amp;quot;LV1&amp;quot;) in the &amp;quot;Set Listview&amp;quot; button.&lt;br /&gt;
===== Attributes =====&lt;br /&gt;
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)&lt;br /&gt;
&lt;br /&gt;
You can specify any valid BR attribute, including Attribute Substitution Statements from your brconfig.sys. This enables the use of BR style themes in your ScreenIO screens.&lt;br /&gt;
&lt;br /&gt;
===== Tooltip Text =====&lt;br /&gt;
Here you can specify the help text, if any, to be associated with the given control. You can specify your own helplevel if you know how to do so. If you do not specify your own help level, ScreenIO defaults to the most unused help level available in the version of BR you&#039;re running. This is level 1 for 4.1 and level 0 for 4.2 or higher, indicating to display the help text as tooltip text whenever the mouse is over the control.&lt;br /&gt;
&lt;br /&gt;
===== User Data =====&lt;br /&gt;
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.&lt;br /&gt;
&lt;br /&gt;
===== Protected =====&lt;br /&gt;
This indicates if a field is protected or not. If its protected, then it is kept automatically out of the input fields statement, keeping the user from modifying it. We do it manually because there are certian times when it doesn&#039;t work properly using the standard BR Protected attribute. However if you wish to use the Standard BR Protected Attribute, you can always specify a &amp;quot;P&amp;quot; in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
===== Invisible =====&lt;br /&gt;
This indicates if a field is invisible or not. If it is invisible, then it is kept off the screen entirely. This is different from BR&#039;s invisible attribute, which hides the data behind a mask of &amp;quot;*&amp;quot;s. If you wish to use the standard BR invisible attribute, you can specify an &amp;quot;I&amp;quot; in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.&lt;br /&gt;
&lt;br /&gt;
==== Listview Columns Editing ====&lt;br /&gt;
If you added a listview to your screen, then when you&#039;re done setting the listviews attributes and you press enter (or click on the listview again), you&#039;ll be taken to Listview Columns Editing Mode. This mode turns the listview temporarily into a grid where you can set the attributes for the individual listivew columns.&lt;br /&gt;
&lt;br /&gt;
If you just added your listview, it will have an empty column in place, to give you something to click on when you&#039;re trying to position it. The first thing to do, is place the cursor in that empty column, and click the Delete Column button to remove that column from the list.&lt;br /&gt;
&lt;br /&gt;
Next, while remaining in Listview Column Mode, click on the Fields listview and select one or more fields to place as columns on the listview, by either Enter or Double Click.&lt;br /&gt;
&lt;br /&gt;
Use the legend on the left to see what each row of the listview means, and specify the attributes for each column in the corresponding rows.&lt;br /&gt;
&lt;br /&gt;
You can also use the keyboard shortcuts Ctrl-Left and Ctrl-Right to move the current column (the column the cursor is in) to the left or the right.&lt;br /&gt;
&lt;br /&gt;
==== Save and Test Screen ====&lt;br /&gt;
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select &amp;quot;Save&amp;quot; from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.&lt;br /&gt;
&lt;br /&gt;
You may now select &amp;quot;Test Screen&amp;quot; from the Screen menu, to test your new screen in a seperate BR process.&lt;br /&gt;
&lt;br /&gt;
==== Conclusion ====&lt;br /&gt;
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn&#039;t have to write any custom code at all.&lt;br /&gt;
&lt;br /&gt;
However, most screens you write will most likely utilize custom code to achieve a nicer effect. You can use your Custom Screen Functions to do just about anything with your ScreenIO Screen. For more details about Custom Screen Functions, see the Custom Screen Function section in this document (below).&lt;br /&gt;
&lt;br /&gt;
=== ScreenIO Custom Screen Functions ===&lt;br /&gt;
You can already see that the ScreenIO system is the fastest way to develop functioning software in the BR world. Simple Listview and FM screens can already be quite powerful, without writing a stitch of custom code. Because of the object oriented database foundation afforded to us by FileIO, we can achieve some pretty amazing results in just a few minutes of graphic design with a WYSIWYG editor.&lt;br /&gt;
&lt;br /&gt;
However, I&#039;m sure you can already think of hundreds of situations where the default ScreenIO behavior is insufficient to achieve the results expected of custom code.&lt;br /&gt;
&lt;br /&gt;
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.&lt;br /&gt;
&lt;br /&gt;
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open and close your screens. You can also place code in the events for your individual controls. You can add custom code to your listview&#039;s Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.&lt;br /&gt;
&lt;br /&gt;
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen&#039;s controls can be referred to by their FileIO syntax in the mat F$ and mat F arrays that are read from your data file. Simply read or change the data in the file record (mat f$ and mat f) and it will be reflected in real time on the screen.&lt;br /&gt;
&lt;br /&gt;
If you place controls on your screen and don&#039;t tie them to a field, but give them a control name instead, then they are placed in a special array called mat S$ and you can access and modify their data values there, by control name.&lt;br /&gt;
&lt;br /&gt;
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ScreenIO Screen Events ====&lt;br /&gt;
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.&lt;br /&gt;
&lt;br /&gt;
===== Form (Screen) Level Events =====&lt;br /&gt;
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.&lt;br /&gt;
====== Enter Event ======&lt;br /&gt;
The Enter Event is triggered when your screen first loads. You can use it to initialize Screen Global Variables, Open additional data files, Initialize values on the screen, and even load other screens that you want to appear to the user as being a part of this screen.&lt;br /&gt;
====== Initialize Event ======&lt;br /&gt;
The Initialize Event is triggered from an Add/Edit screen when you are adding a new record to the data file. This happens any time you call FnFM without specifying the key to edit. (See Using Screens above). Use the Initialize Event to initialize the data in a new record that you are adding.&lt;br /&gt;
&lt;br /&gt;
It is often useful to have your Initialize Event Function call your Read Event Function.&lt;br /&gt;
====== Read Event ======&lt;br /&gt;
The Read Event is triggered upon a successful read of the data file. This happens in an Add/Edit screen any time you are loading a record to modify it.&lt;br /&gt;
&lt;br /&gt;
You most often use this event to Unpack the data from the data file for Screen Display purposes. This is why you sometimes want it to happen on Initialization of new records as well as the reading of existing records.&lt;br /&gt;
&lt;br /&gt;
====== Listview Read Event ======&lt;br /&gt;
On a listview screen, the Read Event behaves totally differently. On a listview screen, you never give a key when you call the screen, so the Read event never gets triggered when the screen is loading.&lt;br /&gt;
&lt;br /&gt;
Instead, on a listview screen, the Read Event is triggered any time the user changes which row is currently selected in your listview. You can use this to update reference information on the screen from the new record in the data file.&lt;br /&gt;
====== Mainloop Event ======&lt;br /&gt;
The mainloop event is an event thats triggered every time the main RINPUT FIELDS statement is executed when running your screenio screen. This means, every time anything happens, the mainloop event happens first. You can use the mainloop event to test for fkey 98 (the windows dropdown menu) and add dropdown menu support to your screenio screen.&lt;br /&gt;
&lt;br /&gt;
You can also place the &amp;quot;X&amp;quot; attribute in various fields to trigger the Mainloop Event to fire whenever the user moves the cursor out of these fields, in order to update the screen in some way.&lt;br /&gt;
&lt;br /&gt;
Another way to use the mainloop event is to use the config keyboard command to remap any key on the keyboard to an fkey value, and test for that fkey value, tying your own custom action to any key on the keyboard.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Mainloop_Function|Mainloop Function]].&lt;br /&gt;
====== Wait Event ======&lt;br /&gt;
The WAIT event is triggered any time your screen has a WAIT value specified in the Window Attributes panel. This event determines the action you would like ScreenIO to take when the keyboard has been idle for some time.&lt;br /&gt;
&lt;br /&gt;
Your WAIT event return value determines the action screenio takes after the main processing of your WAIT event. If your WAIT event function returns True, then ScreenIO clears the WAIT condition and continues executing the screen until another event is triggered. If your WAIT event function returns False, then the ScreenIO screen is closed with an [[#ExitMode|ExitMode]] of Cancel, and the screen is backed out of.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a WAIT event function, then the default ScreenIO WAIT event code fires, and ScreenIO informs the user that their keyboard has been idle for some time, and requests that they please press a key sometime in the next 30 seconds or else they will be logged out of the current screen. If they press a key in the alotted time, they are taken back to the RINPUT FIELDS statement and allowed to continue using the screen. If not, the screen closes and logs them out, freeing up the record so someone else can use it.&lt;br /&gt;
&lt;br /&gt;
====== Locked Record Event ======&lt;br /&gt;
The Locked Record event is triggered any time ScreenIO attempts to read a record that has been locked by another user. Your Locked Record event should tell ScreenIO what to do when a record locking error occurs in your screen.&lt;br /&gt;
&lt;br /&gt;
If your Locked Record event returns True, then the read is attempted again. If it returns false, then the read is cancelled and the screen is exited.&lt;br /&gt;
&lt;br /&gt;
If you do not specify a Locked Record event function, then the default ScreenIO Locked Record event code fires. The user is informed of a file sharing violation and the user name of the person who has the record locked. They are given the option to Retry or Cancel the operation. If they select Retry, the read is attempted again. if they select false, then the read is cancelled and the screen is exited.&lt;br /&gt;
====== Write Event ======&lt;br /&gt;
The Write Event happens just before your screen exits, when Save has been selected. You can use the Write event to perform last minute validation. From the Write Event, you can correct any validation problems, discard the invalid data, or cancel the [[#ExitMode|ExitMode]], forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.&lt;br /&gt;
====== Merge Event ======&lt;br /&gt;
This function gets called only as a result of selecting the &amp;quot;Dont Lock&amp;quot; checkbox for one or more of your screens. When you select that checkbox, BR record locking is disabled, allowing multiple users to edit the same data records at the same time. If that happens, its possible for one users changes to clobber another users changes.&lt;br /&gt;
&lt;br /&gt;
When ScreenIO detects that this has happened (the file record on disk at the time of save is different then what it was when the screen was loaded) it attempts to merge the changes together using one of three methodologies. If AutoMerge is selected, then it attempts to keep the latest version of all fields, keeping the changes made by both users, and if both users changed the same field, it just goes with the current users changes assuming they&#039;re newer because they clicked &amp;quot;save&amp;quot; last. It is recommended to only use the AutoMerge functionality for really simple data files.&lt;br /&gt;
&lt;br /&gt;
If AutoMerge is not selected, it next looks to see if you specified a Merge Event function. Your Merge Event function will then be run to merge the two data elements together.&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t select AutoMerge OR a Merge Event function, then it attempts to do a Postit Note Merge, by reloading the screen with the other persons changes, and listing all your changes in little postit notes next to the fields, that you can click on to enter your changes again.&lt;br /&gt;
====== NoKey Event ======&lt;br /&gt;
This function is run when a key cannot be found. Its here so that if you don&#039;t like the standard ScreenIO &amp;quot;key not found&amp;quot; error, you can write your own.&lt;br /&gt;
&lt;br /&gt;
====== Listview Prepopulate ======&lt;br /&gt;
The listview prepopulate function runs before your listview is populated, so you can open related files, reset counters, or anything else you need to do every time prior to repopulating the listview.&lt;br /&gt;
&lt;br /&gt;
====== Listview Postpopulate ======&lt;br /&gt;
The listview postpopulate function runs after your listview population is complete, so you can close those same files, evaluate the counters, or whatever else you need to do each time your listviews finish populating.&lt;br /&gt;
&lt;br /&gt;
====== Exit Event ======&lt;br /&gt;
The Exit Event happens when the screen exits. If you had to open reference data files in your screens &amp;quot;Enter&amp;quot; event, then the &amp;quot;Exit&amp;quot; event is a good place to close those same data files.&lt;br /&gt;
===== Default Event Functions =====&lt;br /&gt;
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called &amp;quot;defaults&amp;quot; under your &amp;quot;function&amp;quot; folder, (so &amp;quot;function\defaults&amp;quot;) and placing the event functions you want in there with the appropriate name.&lt;br /&gt;
&lt;br /&gt;
If the file is called enter.brs, for example, then it will be run IN ADDITION TO the normal enter event, for all of your screens.&lt;br /&gt;
&lt;br /&gt;
This can be used in conjunction with the new screen level UserData$ field, to make system wide event functions that run for just the screens you want. Simply test the value of ScreenIO$(si_userdata) at the beginning of your function and react accordingly, then set UserData$ for each of your screens that you want the function to apply to.&lt;br /&gt;
&lt;br /&gt;
Every Screen Level event function is supported, enter.brs, init.brs, read.brs, prelist.brs, postlist.brs, nokey.brs, merge.brs, write.brs, exit.brs, mainloop.brs, wait.brs, locked.brs, etc.&lt;br /&gt;
&lt;br /&gt;
===== Control Specific Events =====&lt;br /&gt;
In addition to the Form Level events, ScreenIO provides one custom event per control. The meaning of this event is different depending on the control type. Some controls don&#039;t have any event at all.&lt;br /&gt;
====== Click Event ======&lt;br /&gt;
The Click Event is the simplest event to code for. It is triggered whenever someone clicks on a Button or a Picture. In this event, you can place any code that you want to be called when they click on the button.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Click_Event_Function|Click Event Function]].&lt;br /&gt;
====== Validate Event ======&lt;br /&gt;
The Validate Event is triggered whenever the data in the element changes. You can use this event to discard or accept the data, display a msgbox to the user, and position the curser. If your validation routine returns non-zero and non-blank, then the value the user typed is accepted and saved. If your validation routine returns null or 0 then the value the user typed in is ignored and the previous value is retained. You can also modify the value directly by modifying the optional parameter &amp;quot;FieldText$&amp;quot; in your function.&lt;br /&gt;
&lt;br /&gt;
See Example [[#Validate_Field_Function|Validate Field Function]].&lt;br /&gt;
====== Filter Event ======&lt;br /&gt;
The Filter function is one of the most versatile functions. This function can be used to unpack the record data so it can be properly displayed in the listview. It can also mark records for inclusion or exclusion in the listview, and if it specifies a color, then that color is used to conditionally color the records of the data file while displaying them in the listview.&lt;br /&gt;
&lt;br /&gt;
Your filter function must return true (non-zero) or something (non-empty string) for all records which are to be included in the listview. Any time your Filter Function returns False (or a null string), the record is ignored.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns a valid color code, (ex: &amp;quot;/#0000FF:000000&amp;quot; a hex code or &amp;quot;[HILITECOLOR]&amp;quot; an attribute substitution statement from your brconfig.sys), then the row is colored that color.&lt;br /&gt;
&lt;br /&gt;
If your filter function returns the word &amp;quot;STOP&amp;quot;, then screenio stops reading the data file and also doesn&#039;t include the record in the list. You can use this function to make listview functions run faster.&lt;br /&gt;
&lt;br /&gt;
To do so, you want to read the record by an appropriate key. (Keep in mind you can set the Read Key for the screen in the Window Attributes in the top left corner.) Then, in your preListview event function, use a [[Restore_File|RESTORE]] command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you&#039;ve moved past the last record that you want to display, return &amp;quot;STOP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]].&lt;br /&gt;
&lt;br /&gt;
====== Conversion Function ======&lt;br /&gt;
The Conversion Function Event is more powerful then many of the other events. It can also contain a function or a reference to a library, but in addition to those values it may contain any valid BR PIC or FMT or DATE statement that can be applied with the &amp;quot;CNVRT$&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
Also, if you&#039;re using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is DATE then ScreenIO will automatically use it to convert what the user typed in back into a natural DATE value.&lt;br /&gt;
&lt;br /&gt;
You may also use the validation function to preform validation on the field. However, if you are using DATE, then remember to leave the accpted value in the DATE format so that ScreenIO can convert it back to the julian DAYS format that you will be saving on disk.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use &amp;quot;val&amp;quot; to change numeric fields back into numeric fields.&lt;br /&gt;
&lt;br /&gt;
If the conversion value is a custom function, then your custom function will need to modify &amp;quot;FieldText$&amp;quot; to the appropriate value for Converting from Disk to Screen. If you then need to convert it back, you may do so through the fields Validation function.&lt;br /&gt;
&lt;br /&gt;
==== Valid Custom Function Types ====&lt;br /&gt;
Your Custom Function can specify several different types of Event Handler. The Edit button is provided to help you manage and reuse your Custom Functions. &lt;br /&gt;
&lt;br /&gt;
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.&lt;br /&gt;
&lt;br /&gt;
===== Link to another screen =====&lt;br /&gt;
To link to another screen, simply specify the Screen Name in Square Brackets:&lt;br /&gt;
&lt;br /&gt;
  Function: [CUSTEDIT]&lt;br /&gt;
  &lt;br /&gt;
  or (specify a position)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT(2,4)]&lt;br /&gt;
  &lt;br /&gt;
  or (pass in other values)&lt;br /&gt;
  &lt;br /&gt;
  Function: [CUSTEDIT]key$=CurrentKey$&lt;br /&gt;
&lt;br /&gt;
You can specify the row and column position to place the new screen using the shorthand notation specified above, placing the row and column in parenthesis inside the square brackets, after the screen name.&lt;br /&gt;
&lt;br /&gt;
You can pass values into the screen you are about to call by specifying them after the name of the screen as in the example above.&lt;br /&gt;
&lt;br /&gt;
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.&lt;br /&gt;
&lt;br /&gt;
====== CurrentKey$ ======&lt;br /&gt;
&lt;br /&gt;
CurrentKey$ always matches the Currently Selected Key from this current screen. If the current screen is a listview, then CurrentKey$ will always match the currently selected row of the listview. This can be used anywhere in your custom functions that you want to know the key for the currently selected or currently edited record.&lt;br /&gt;
&lt;br /&gt;
By saying &amp;quot;Key$=CurrentKey$&amp;quot; in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.&lt;br /&gt;
&lt;br /&gt;
====== ThisParentKey$ ======&lt;br /&gt;
&lt;br /&gt;
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use &amp;quot;ParentKey$&amp;quot; to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you&#039;re calling, you&#039;ll need to use ThisParentKey$.&lt;br /&gt;
&lt;br /&gt;
If you say &amp;quot;ParentKey$=ThisParentKey$&amp;quot; then you&#039;re telling screenio to use the ParentKey$ from this screen to set the ParentKey$ in the new child screen. This is useful when you need to pass your ParentKey$ or part of it into a child screen as the parentkey for that child screen.&lt;br /&gt;
&lt;br /&gt;
===== Chain statement =====&lt;br /&gt;
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.&lt;br /&gt;
&lt;br /&gt;
  %menu.br&lt;br /&gt;
&lt;br /&gt;
This example will chain to the BR program called &amp;quot;menu.br&amp;quot;.&lt;br /&gt;
===== Any single BR command =====&lt;br /&gt;
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.&lt;br /&gt;
&lt;br /&gt;
The only exception to this is the Conversion Function. If you type anything else in the Conversion Function, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. &lt;br /&gt;
&lt;br /&gt;
You can launch a web page or a system command here, or you can modify the status of the current screen. You might have a Save button with a click event that says:&lt;br /&gt;
&lt;br /&gt;
  let ExitMode=SaveAndQuit&lt;br /&gt;
&lt;br /&gt;
[[#ExitMode|ExitMode]] is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant &amp;quot;SaveAndQuit&amp;quot; then your screen will exit and save the data on its way out.&lt;br /&gt;
&lt;br /&gt;
===== Any valid BR Field Spec (Conversion Function Only) =====&lt;br /&gt;
If you type anything in the Conversion Function thats not a library call or a custom function reference, then it will be interpreted as a BR Field Spec to be used with the CNVRT$ function. Any valid field spec, including FMT and PIC and DATE are acceptable here.&lt;br /&gt;
&lt;br /&gt;
ScreenIO will use this value to convert the data as best it can both onto the screen and back onto the disk. If you are using Julian Date values on the disk, you&#039;ll probably want to specify a &amp;quot;DATE(&amp;quot; conversion function to automatically have those displayed and edited as readable dates. You can also use this for numeric formatting, and listview sorting if you put it in a listview column.&lt;br /&gt;
&lt;br /&gt;
Listview numeric column sorting is only available in BR 4.2. BR 4.1 and earlier will sort the numeric fields alphabetically which does not always produce the desired results.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Custom Screen Function =====&lt;br /&gt;
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.&lt;br /&gt;
&lt;br /&gt;
  {AddNewCustomer}&lt;br /&gt;
&lt;br /&gt;
More details about Custom Screen Functions follow.&lt;br /&gt;
&lt;br /&gt;
====== Entering / Selecting your custom handler ======&lt;br /&gt;
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the &amp;quot;Edit&amp;quot; button. This button brings up the ScreenIO Select Custom Screen Function dialog.&lt;br /&gt;
&lt;br /&gt;
At the top left you&#039;ll see a list of all your available Custom Screen Functions. At the bottom left is a search box, that can be used to hunt quickly through the list of Custom Screen Functions, as well as to specify the name for new Custom Screen Functions that you might create. At the right of the dialog is a multi-line text box displaying the first part of the source code for the currently selected Custom Screen Function.&lt;br /&gt;
&lt;br /&gt;
You can select any Custom Function from the list and click the &amp;quot;Ok&amp;quot; button to accept it.&lt;br /&gt;
&lt;br /&gt;
===== Link to a Library Function =====&lt;br /&gt;
You may also link directly to a library function from any of your Screen Events. To do this, type a &amp;quot;#&amp;quot; followed by the library name and the function, separated by a &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  #libname:fnFunctionName(parm1,parm2$,parm3)&lt;br /&gt;
&lt;br /&gt;
Example: Assume your library is called &amp;quot;run.br&amp;quot; and your function is called fnRun(screenname$).&lt;br /&gt;
&lt;br /&gt;
  #run:fnRun(&#039;customer&#039;)&lt;br /&gt;
&lt;br /&gt;
Example 2: Assume your library is called &amp;quot;thing.dll&amp;quot; and your function is called fnDoSomething(thing$,otherthing$)&lt;br /&gt;
&lt;br /&gt;
  #thing.dll:fnDoSomething(thing$,&#039;constant&#039;)&lt;br /&gt;
&lt;br /&gt;
Note: Notice the use of single quotes when passing string constants into your library functions. This is necessary at this time because of the way ScreenIO compiles your custom helper libraries.&lt;br /&gt;
&lt;br /&gt;
==== Writing Screen Helper Functions ====&lt;br /&gt;
&lt;br /&gt;
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the &amp;quot;Add New&amp;quot; button. ScreenIO automatically creates a new .brs file containing a blank custom screen function, and opens it in your Windows Default Editor for .BRS files. If you don&#039;t have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.&lt;br /&gt;
&lt;br /&gt;
You will notice that your new blank Custom Screen Function doesn&#039;t have any line numbers in it. This is important. When ScreenIO compiles all your individual Custom Screen Functions into one Autogenerated Screen Helper Library for each Screen, it has to add the line numbers itself, to make sure that none of them conflict with each other. Therefore, when you write Custom Screen Functions, it is important to remember not to use line numbers in your code.&lt;br /&gt;
&lt;br /&gt;
===== Custom Screen Function Parameters =====&lt;br /&gt;
&lt;br /&gt;
ScreenIO Provides several parameters automatically that you can use in your Screen Functions. If you wish to make use of a parameter, all you have to do is add it as a required parameter in your Custom Function Definition statement. ScreenIO actually checks your custom function statements to see which variables they are expecting and provides them with all the variables they ask for, as long as they are on this list:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Function$&#039;&#039;&#039; - The Function we are Calling&lt;br /&gt;
*&#039;&#039;&#039;Mat F$&#039;&#039;&#039; - The Strings for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat F&#039;&#039;&#039; - The Numbers for the FileIO Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat S$&#039;&#039;&#039; - Your Screen Record Object&lt;br /&gt;
*&#039;&#039;&#039;Mat Form$&#039;&#039;&#039; - Your FileIO Forms Array&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;All your Screen Information&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio$&#039;&#039;&#039; - Your Screen Header information (Strings)&lt;br /&gt;
**&#039;&#039;&#039;Mat Screenio&#039;&#039;&#039; - Your Screen Lines information (Numbers)&lt;br /&gt;
**&#039;&#039;&#039;mat ControlName$&#039;&#039;&#039; - Array of the control names for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldName$&#039;&#039;&#039; - Array of the Field Names for the associated fields of all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Description$&#039;&#039;&#039; - Array of the Descriptions or Caption Fields for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat VPosition&#039;&#039;&#039; - Array of the Verticle Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat HPosition&#039;&#039;&#039; - Array of the Horizontal Position for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FieldType$&#039;&#039;&#039; - Array of the Field Types for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat SpecWidth&#039;&#039;&#039; - Array of the Spec Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Width&#039;&#039;&#039; - Array of the Widths for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Height&#039;&#039;&#039; - Array of the Heights for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat TrueValue$&#039;&#039;&#039; - Array of the Truth Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FalseValue$&#039;&#039;&#039; - Array of the Falsehood Values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Function$&#039;&#039;&#039; - Array of the Function triggers for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Picture$&#039;&#039;&#039; - Array of the Picture Files for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Parent$&#039;&#039;&#039; - Array of the Parent Attribute for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat FGColor$&#039;&#039;&#039; - Array of the Foreground Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat BGColor$&#039;&#039;&#039; - Array of the Background Colors for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Justify$&#039;&#039;&#039; - Array of the Justification Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Attr$&#039;&#039;&#039; - Array of the Additional Attribute Specs for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat Protected&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are protected.&lt;br /&gt;
**&#039;&#039;&#039;mat Invisible&#039;&#039;&#039; - Array of boolean flag indicating weather or not each of your controls are invisible.&lt;br /&gt;
**&#039;&#039;&#039;mat Tooltip$&#039;&#039;&#039; - Array of the tooltip help text for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtIn$&#039;&#039;&#039; - Array of the conversion values for all the controls on your screen.&lt;br /&gt;
**&#039;&#039;&#039;mat ConvrtOut$&#039;&#039;&#039; - Not currently used.&lt;br /&gt;
**&#039;&#039;&#039;mat MultiSelect&#039;&#039;&#039; - Array of values indicating weather or not your Listviews have Multiselect Enabled.&lt;br /&gt;
**&#039;&#039;&#039;mat Userdata$&#039;&#039;&#039; - Array of data passed into your screen that can be used for any reason&lt;br /&gt;
*&#039;&#039;&#039;mat Subscripts$&#039;&#039;&#039; - This array contains your FileIO Subscripts and your ScreenIO Subscripts and the sio_ subscripts for all your controls that are not tied to a field and are instead living inside your mat S$ array.&lt;br /&gt;
*&#039;&#039;&#039;mat ControlSpec$&#039;&#039;&#039; - This is an array showing the calculated output spec for each of your controls. You can access it like: ControlSpec$(ctl_Listview) to get the control spec of a field named &amp;quot;listview&amp;quot;.&lt;br /&gt;
*&#039;&#039;&#039;Key$&#039;&#039;&#039; - This is the Key that we called the screen with&lt;br /&gt;
*&#039;&#039;&#039;[[#ExitMode|ExitMode]]&#039;&#039;&#039; - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawListviews&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the whole listview, from the headers on up, when its done processing your custom function code.&lt;br /&gt;
*&#039;&#039;&#039;RedrawFrames&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.&lt;br /&gt;
*&#039;&#039;&#039;RedrawScreens&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.&lt;br /&gt;
*&#039;&#039;&#039;RepopulateCombo&#039;&#039;&#039; - Set this value to True in your function to cause ScreenIO to rerun all your &amp;quot;RepopulateCombo&amp;quot; functions and repopulate all the combo boxes on your screen.&lt;br /&gt;
*&#039;&#039;&#039;Prefix$&#039;&#039;&#039; - Prefix for your FileIO Data File&lt;br /&gt;
*&#039;&#039;&#039;Currentkey$&#039;&#039;&#039; - Currently selected key from your data file&lt;br /&gt;
*&#039;&#039;&#039;rec(datafile)&#039;&#039;&#039; - this is obvious, but if you need to know the current record in the primary data file you can use the BR system function REC to discover it.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedKeys$&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to CurrentKey$ above. Therefore you can use Mat SelectedKeys$ to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat SelectedRecords&#039;&#039;&#039; - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. If Multiselect is not enabled, then this array will have only one element and it will be equivlent to rec(Datafile) above. Therefore you can use Mat SelectedRecords to write functions that work for both multi-select listviews and single selection listviews.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F$&#039;&#039;&#039; - this is an automatic copy of Mat F$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_F&#039;&#039;&#039; - this is an automatic copy of Mat F that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat Save_S$&#039;&#039;&#039; - this is an automatic copy of mat S$ that is made upon entering the screen and can be used to determine weather or not the user has changed anything sense reading or adding the record.&lt;br /&gt;
*&#039;&#039;&#039;mat PassedData$&#039;&#039;&#039; - this array can be used for any purpose you desire. It represents an array of data you can pass into your screen with the call to fnfm. You can query it and use it in your custom functions in whatever way you desire.&lt;br /&gt;
*&#039;&#039;&#039;Parentkey$&#039;&#039;&#039; - The Parent Key that may have been passed into your screen when it was called. This is a value that you can pass into your screens that has no purpose except to be used in your screen functions. You can use it to filter your listview to show only records for the current Customer or whatver ParentKey makes sense to you.&lt;br /&gt;
*&#039;&#039;&#039;LockUser$&#039;&#039;&#039; - This value is only available in the Record Locked event. It will tell you the user name of the user who has the record locked.&lt;br /&gt;
*&#039;&#039;&#039;Datafile&#039;&#039;&#039; - This is the file number of the data file&lt;br /&gt;
*&#039;&#039;&#039;Window&#039;&#039;&#039; - This is the window number of the screenio screen&lt;br /&gt;
*&#039;&#039;&#039;FileIO Subscripts&#039;&#039;&#039; - All your fileio subscripts are set for you so you may use your file just as if you&#039;d opened it yourself.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Subscripts&#039;&#039;&#039; - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.&lt;br /&gt;
*&#039;&#039;&#039;ScreenIO Control Subscripts&#039;&#039;&#039; - Every Control on your screen with a control name has a subscript that can be used to access its properties in the Screen Control Arrays above. For example, if you have a text box named &amp;quot;Customer&amp;quot; and you want to make it invisible in one of your custom helper functions, then give the command: &amp;quot;let Invisible(ctl_customer)=1&amp;quot;&lt;br /&gt;
*&#039;&#039;&#039;CurrentRow&#039;&#039;&#039; - this variable contains and controls the currently selected listview element. You can use it to determine which listview item is currently selected, and if you change this value it will change the current row in the listview. You can use this value to control the cursor on a listview screen.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield&#039;&#039;&#039; - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.&lt;br /&gt;
*&#039;&#039;&#039;Currentfield$&#039;&#039;&#039; - This is Control Name of the Control for the field which the cursor is in. You can move the cursor by setting CurrentField$ to the ControlName$ of the field you want to move it to. This is case insensitive. If you change both CurrentField$ and CurrentField, the CurrentField$ change takes precedence.&lt;br /&gt;
*&#039;&#039;&#039;DisplayOnly&#039;&#039;&#039; - This boolean flag tells if the screen is currently running (accepting input) or if its just being displayed. You can use it to trigger user interface changes to let your users know what part of the program is active at the given moment.&lt;br /&gt;
*&#039;&#039;&#039;Selecting&#039;&#039;&#039; - This is a parameter that can be passed into ScreenIO when calling a screen for your own purposes. Its not used by ScreenIO at all. You can use it to signal a multipurpose screen that it should be used in Selecting mode, and then make your custom functions react accordingly. Its available in your custom functions so that you can test its value.&lt;br /&gt;
*&#039;&#039;&#039;&#039;&#039;Only Available in Validate and Conversion Functions&#039;&#039;&#039;&#039;&#039; - these next parameters are only available in Validate and Conversion functions. Most of them are read only (any changes to them will be ignored) and they should be used to make your custom Validation and Conversion functions reusable:&lt;br /&gt;
**&#039;&#039;&#039;Fieldtext$&#039;&#039;&#039; - This is the text in the field being validated/converted.&lt;br /&gt;
**&#039;&#039;&#039;Fieldindex (read only)&#039;&#039;&#039; - This is the CurFld value of the field being validated/converted. You could use this to put the cursor in the bad field by saying &#039;&#039;&amp;quot;CurrentField=FieldIndex&amp;quot;&#039;&#039;.&lt;br /&gt;
**&#039;&#039;&#039;ControlIndex (read only)&#039;&#039;&#039; - This is the index (matches ctl_controlname) of the Control for the field being validated/converted. You can use this anywhere that you can use ctl_controlname, for example to access the Attributes arrays of the control. For example, you can make the control invisible by saying &#039;&#039;&amp;quot;Invisible(ControlIndex)=1&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Accessing Control Properties from within your Helper Functions =====&lt;br /&gt;
If you wish to access any of your controls&#039; attributes from a custom helper function, you first have to define the control by giving it a ControlName in the Control Attributes Window. Then, all you have to do is reference the array of the attribute you&#039;re looking for, with the control name for a subscript, prefixed by &amp;quot;ctl_&amp;quot;. For example, to make the customer control invisible, simply type:&lt;br /&gt;
&lt;br /&gt;
  let Invisible(ctl_customer)=1&lt;br /&gt;
&lt;br /&gt;
===== #Include Statement =====&lt;br /&gt;
Sometimes it is necessary to reference one of your custom helper functions from another one. But when you do, you need a way to ensure that its always included in any screens that call the first custom helper function. The way to do that is with the #Include statement. You use this statement in a comment, so that BR will ignore it. Simply say:&lt;br /&gt;
&lt;br /&gt;
  ! #Include {functionname}&lt;br /&gt;
&lt;br /&gt;
in a comment somewhere in your program and the specified custom helper function will be included. The &amp;quot;{}&amp;quot;s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
===== Examples =====&lt;br /&gt;
&lt;br /&gt;
====== Validate Field Function ======&lt;br /&gt;
&lt;br /&gt;
NOTE: ScreenIO has this functionality built in now, so you shouldn&#039;t need to validate your dates this way. Its only included here as an example for how a validate function works.&lt;br /&gt;
&lt;br /&gt;
For more information on the proper way to work with dates in ScreenIO, see the [[#Conversion_Function|Conversion Function]] section.&lt;br /&gt;
&lt;br /&gt;
  ! function\validatedate.brs&lt;br /&gt;
  !&lt;br /&gt;
  ! Created on 01/12/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! This function would be placed in every field in the SageLive system that accepts a date.&lt;br /&gt;
  ! &lt;br /&gt;
  !&lt;br /&gt;
  def fnvalidatedate(&amp;amp;fieldtext$;___,DateValue)  &lt;br /&gt;
     let DateValue=days(fieldtext$,&amp;quot;mm/dd/ccyy&amp;quot;) conv BadDateEntered&lt;br /&gt;
  &lt;br /&gt;
     let fieldtext$=date$(DateValue,&amp;quot;m/d/ccyy&amp;quot;)&lt;br /&gt;
     let fnvalidatedate=1 ! Date Save Successful  &lt;br /&gt;
  &lt;br /&gt;
     BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back.&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Listview Filter Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\filtertasks.brs&lt;br /&gt;
  ! Created on 04/17/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnFilterTasks - This Function Filters the Tasks List to show only&lt;br /&gt;
  !  tasks for the Current Employee that are not completed or cancelled. &lt;br /&gt;
  !  It also colors the tasks, and sets the task_status Listview Column.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is the filter event for the Todo List listview in the SageLive System&lt;br /&gt;
  !&lt;br /&gt;
  dim CurrentEmployee$&lt;br /&gt;
  &lt;br /&gt;
  def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$)&lt;br /&gt;
     &lt;br /&gt;
     if CurrentEmployee$=&amp;quot;&amp;quot; then&lt;br /&gt;
        library &amp;quot;timelib&amp;quot; : fnCurrentEmployee$&lt;br /&gt;
        let CurrentEmployee$=fnCurrentEmployee$&lt;br /&gt;
     end if&lt;br /&gt;
     if uprc$(ParentKey$(1:7))=&amp;quot;SHOWALL&amp;quot; then&lt;br /&gt;
        if f$(todo_employee)=CurrentEmployee$ then&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#00FF00:#000000&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
           let fnFilterTasks$=&amp;quot;/#0000FF:#000000&amp;quot;&lt;br /&gt;
        end if&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#33CC66:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;X&amp;quot; ! Open&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#6699FF:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Y&amp;quot; ! Completed&lt;br /&gt;
     else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then&lt;br /&gt;
        let fnFilterTasks$=&amp;quot;/#AA0000:#000000&amp;quot;&lt;br /&gt;
        if sio_taskstatus then let s$(sio_taskstatus)=&amp;quot;Z&amp;quot; ! Cancelled&lt;br /&gt;
     end if&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
====== Click Event Function ======&lt;br /&gt;
&lt;br /&gt;
  ! function\quickinvoiceacustomer.brs&lt;br /&gt;
  ! Created on 03/30/2009&lt;br /&gt;
  !&lt;br /&gt;
  ! fnQuickInvoiceACustomer - This Function automatically creates an invoice&lt;br /&gt;
  !  for a customer.&lt;br /&gt;
  !&lt;br /&gt;
  ! This function is placed in the Click Event for the &amp;quot;Invoice Customer&amp;quot; button on the&lt;br /&gt;
  !  Customer Listview Screen in the SageLive system.&lt;br /&gt;
  !&lt;br /&gt;
  ! It operates on the currently selected item in the listview by using the&lt;br /&gt;
  !  value of CurrentKey$&lt;br /&gt;
  ! &lt;br /&gt;
  ! Most of the actual processing takes place in various libraries that are part&lt;br /&gt;
  !  of the SageLive system.&lt;br /&gt;
    &lt;br /&gt;
  dim Invoice$(1)*255,Invoice(1)&lt;br /&gt;
  &lt;br /&gt;
  def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$)&lt;br /&gt;
     library &amp;quot;invclib&amp;quot; : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData&lt;br /&gt;
  &lt;br /&gt;
     let Invoice=fnOpen(&amp;quot;invoice&amp;quot;,mat Invoice$,mat Invoice,mat Form$)&lt;br /&gt;
  &lt;br /&gt;
     let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice)&lt;br /&gt;
     let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$)&lt;br /&gt;
     let fnImportCustomer(CurrentKey$,Invoice$(ih_id))&lt;br /&gt;
     let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1)&lt;br /&gt;
  &lt;br /&gt;
     write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice&lt;br /&gt;
     let fnCloseFile(Invoice,&amp;quot;invoice&amp;quot;)&lt;br /&gt;
  &lt;br /&gt;
     let fnfm(&#039;INVCEDIT&#039;,Invoice$(ih_id))&lt;br /&gt;
  fnend&lt;br /&gt;
&lt;br /&gt;
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.&lt;br /&gt;
&lt;br /&gt;
The next two functions, fnAddCustomerToInvoice and fnImportCustomer add the customer to the invoice, automatically searching the database for any billable work that has been completed, and adding it to the invoice. They also mark the timelog records as &amp;quot;Billed&amp;quot;, and mark the invoice number in the timelog record showing which invoice each timelog entry ended up on. At the same time, they populate the Invoice Header record with important information such as Billing Address, Shipping Information, Payment Terms, etc.&lt;br /&gt;
&lt;br /&gt;
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we&#039;re running BR 4.2 or 4.1. If we&#039;re running BR 4.1, then it generates the PDF file using the CutePDF Printer Driver and a short AutoIt Script. If its BR 4.2, then it uses the built in PDF generation ability. The optional parameter 1 at the end specifies to generate the PDF file. The same function could be used to print the invoice on a standard printer using Print Preview and the windows Printer selection dialog.&lt;br /&gt;
&lt;br /&gt;
After that we write the new invoice to the database, and the file is closed.&lt;br /&gt;
&lt;br /&gt;
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.&lt;br /&gt;
&lt;br /&gt;
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.&lt;br /&gt;
&lt;br /&gt;
====== Mainloop Function ======&lt;br /&gt;
&lt;br /&gt;
Now lets take a look at how to use the Mainloop Function to respond to various keys.&lt;br /&gt;
&lt;br /&gt;
  ! function\tabsmainloop.brs&lt;br /&gt;
  ! Created on 02/21/2010&lt;br /&gt;
  !&lt;br /&gt;
  ! fnTabsMainloop - This Function This Function updates the Current Potential&lt;br /&gt;
  !  elements of the Screen (if they exist)&lt;br /&gt;
  !&lt;br /&gt;
  ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu.&lt;br /&gt;
  !  it also does a few other things for some of the screens it sits in.&lt;br /&gt;
  !&lt;br /&gt;
  ! #Include {executetask}&lt;br /&gt;
  ! #Include {tabwindowsmenu}&lt;br /&gt;
  &lt;br /&gt;
    def fnTabsMainloop&lt;br /&gt;
       if fkey=98 then let fnProcessWindowsMenu  ! Fkey 98 is Windows Menu Click&lt;br /&gt;
       if fkey=0 or fkey=201 then let fnSelect   ! Fkey 0 is Enter and Fkey 201 is Double Click&lt;br /&gt;
  &lt;br /&gt;
       if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential&lt;br /&gt;
    fnend&lt;br /&gt;
   &lt;br /&gt;
    def fnSelect&lt;br /&gt;
       if lwrc$(screenio$(si_screencode))=&amp;quot;tabwork&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;projedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabtodo&amp;quot; then&lt;br /&gt;
          if todo_function and len(trim$(f$(todo_function))) then&lt;br /&gt;
             let fnExecuteTask&lt;br /&gt;
          else&lt;br /&gt;
             let fnfm(&amp;quot;taskedit&amp;quot;,CurrentKey$)&lt;br /&gt;
          end if&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabincome&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;invcedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabexpense&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;expnedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       else if lwrc$(screenio$(si_screencode))=&amp;quot;tabcustomer&amp;quot; then&lt;br /&gt;
          let fnfm(&amp;quot;custedit&amp;quot;,CurrentKey$)&lt;br /&gt;
       end if&lt;br /&gt;
       if fkey&amp;lt;&amp;gt;93 then let fkey(-1) ! Reset Fkey after whatever they&#039;ve done except Windows X&lt;br /&gt;
       let Function=-1&lt;br /&gt;
       let ExitMode=0 ! Don&#039;t exit after procesing Enter Key&lt;br /&gt;
    fnend&lt;br /&gt;
&lt;br /&gt;
The fnTabsMainLoop function is used here to check for various special function keys that we want to do something special for, as well as to do any processing that we wish to run as often as possible.&lt;br /&gt;
&lt;br /&gt;
The first thing it does is test for and respond to a Windows Dropdown Menu click (fkey 98). If a selection is made from the Windows Dropdown Menu, the SageLive Windows Menu handler is called. This Windows Menu Handler function resides in another Custom Function which we include using the #Include screenio command. This command is used any time one of your custom functions depends on another custom function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After that we check for the Enter Key (fkey 0) or a Double Click (fkey 201). The default action in ScreenIO for the enter key, is to select the current item from the list and return it to the calling code, exiting the screen. But for many of the listveiws in the SageLive system, we wanted to do something different. In many cases we wanted to view or edit the item selected, and in one case, the SageLive Todo List, we wanted to do something really special.&lt;br /&gt;
&lt;br /&gt;
We&#039;re testing for fkey 201 because I also want double clicking on a listview item to preform our special &amp;quot;Selection&amp;quot; routine.&lt;br /&gt;
&lt;br /&gt;
Because this function is used in many different screens, and they each display different information and require a different action, I chose to place the code that handles the event inside another function, fnSelect.&lt;br /&gt;
&lt;br /&gt;
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we&#039;re in, and handles the click accordingly. For example, if we&#039;re on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we&#039;re on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SageLive Todo List contains one special feature. Todo List Items can have code in them, a function that gets executed automatically to help with the task. For example, the automatic task that comes up each month to remind me to enter the electric bill has code in it that helps me enter the electric bill as an expense into the system.&lt;br /&gt;
&lt;br /&gt;
When I run that task, SageLive automatically launches my electric bills website for me, right at the login prompt. Then it waits with an autoit script for me to print the latest bill from their webpage. I select &amp;quot;Print Bill&amp;quot; from the electric companies website, and the bill is snatched right from the print stream and uploaded into SageLive. I read and enter the amount on the bill, and the rest is done for me.&lt;br /&gt;
&lt;br /&gt;
Here you see where we call the ExecuteTask function responsible for that piece of magic, whenever an item is selected on the SageLive Todo List. If the Task we selected has code in it, then we run the code, executing the task. If it does not have code in it, then we simply launch the Task View screen where the text in the Todo List item can be read in a multi-line text box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At the end of the fnSelect Routine is code to reset the fkey value and to cancel the default action for the Enter key (which is to select and quit). Fkey 93 is the Windows X, and in ScreenIO it means to exit every screen that we&#039;re in (prompting to save any changes) and if your original calling program that launched the first screen responds to it properly, close BR. So we want to leave fkey 93 alone but cancel any other fkey values that might have come back from the screen we jumped into.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After handling the special keys, our fnTabsMainLoop function handles the fnUpdateCurrentPotential. Some of the screens in the SageLive system have a little place where they show the Current Employee&#039;s Current Potential Earnings. This function is called from lots of screens and only a few of those have the Current Potential Display, so the first thing we do is test to see if the screen we&#039;re currently in has the Current Potential fields on it. &lt;br /&gt;
&lt;br /&gt;
The Current Potential Fields is a calculated approximation of how much money the Current Employee has earned so far today, and how much money they can potentially earn if they continue to work until 6pm.&lt;br /&gt;
&lt;br /&gt;
It was intended to be a motivational tool, but its mentioned here as an example of a situation where you might want to update some data on the screen as often as possible. Because the Current Earnings are always going up whenever the employee is currently logged in on a project, and the Potential Earnings are always going down whenever the employee is not logged in on a project, we want to try to update it as often as we can.&lt;br /&gt;
&lt;br /&gt;
The mainloop is called every single time ScreenIO gets control and the RINPUT FIELDS statement ends. The Screens with Current Potential fields are all listview screens with the X attribute specified for the listview, making it so that any time the user scrolls around the list, presses the fkey, clicks on any button or does just about anything at all, the Current Potential is updated. You can even use this in combination with the Wait Time value to force a regular update of the screen.&lt;br /&gt;
&lt;br /&gt;
===== ScreenIO Built In functions =====&lt;br /&gt;
ScreenIO has a built in function for use in your events.&lt;br /&gt;
====== FnFindSubscript ======&lt;br /&gt;
FnFindSubscript(mat Subscripts$,Prefix$,String$)&lt;br /&gt;
This function searches through the array mat Subscripts$ looking for the subscript that matches the given Prefix$ and Subname$. It returns the index of this subscript.&lt;br /&gt;
&lt;br /&gt;
Use this function to programmatically interrogate mat Subscripts$ from your Custom Functions in order to help make them more reusable.&lt;br /&gt;
&lt;br /&gt;
===== Mat S$ =====&lt;br /&gt;
Lets go over a couple of ScreenIO Concepts one more time.&lt;br /&gt;
&lt;br /&gt;
Most of the controls on the screen are tied directly to a field in the data file. In your Custom Validation Functions, you can refer to that data by its FileIO Name.&lt;br /&gt;
&lt;br /&gt;
  let msgbox(&amp;quot;Customer Name is &amp;quot;&amp;amp;f$(cu_Name))&lt;br /&gt;
&lt;br /&gt;
The value in your mat F$ and mat F is the same as the value on the screen. It is the value of the disk record in memory. When the record is saved, mat F$ and mat F are rewritten back to the data file.&lt;br /&gt;
&lt;br /&gt;
However, any of your controls that are NOT tied to a data file, (but still have a control name) get placed in another array: Mat S$&lt;br /&gt;
&lt;br /&gt;
A Control is tied to the data file if it has a value for its FieldName. Mat S$ contains the data for all the controls that have no value for &amp;quot;FieldName&amp;quot; but do have a value for &amp;quot;ControlName&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can access them the data in Mat S$ by giving the screenIO subscript for the control, which is sio_ControlName where ControlName is the actual name of your control.&lt;br /&gt;
&lt;br /&gt;
  read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer&lt;br /&gt;
  let S$(sio_CustomerName)=Customer$(cu_FirstName)&amp;amp;&amp;quot; &amp;quot;&amp;amp;Customer$(cu_LastName)&lt;br /&gt;
&lt;br /&gt;
You can use this feature to have additional input fields that the end user is able to interact with that don&#039;t necessarily correspond directly with a field in the data file. Your Custom Functions can react to the mat S$ fields and they can also update the Mat S$ fields.&lt;br /&gt;
&lt;br /&gt;
You can use a Mat S$ field to set the picture file for a picture control, to something that is calculated in a Custom Function at runtime.&lt;br /&gt;
&lt;br /&gt;
===== ExitMode =====&lt;br /&gt;
&lt;br /&gt;
One common thing you might do in a custom function, or directly in one of your controls Function properties is set ExitMode. ExitMode is a variable you can change with your custom functions. It governs when your screen is finished executing.&lt;br /&gt;
&lt;br /&gt;
ExitMode can have the following values:&lt;br /&gt;
&lt;br /&gt;
*ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.&lt;br /&gt;
*ExitMode=SaveAndQuit .... When ExitMode is SaveAndQuit then the screen stops running and the data is saved and the key of the new record is returned. Use this on an Add/Edit Screen.&lt;br /&gt;
*ExitMode=SelectAndQuit .... When ExitMode is SelectAndQuit then the screen stops running and the key of the currently selected listview item is returned. Use this on a Listview Screen.&lt;br /&gt;
*ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.&lt;br /&gt;
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.&lt;br /&gt;
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they&#039;d like to Save or just Quit, and behave accordingly. If the user hasn&#039;t changed anything, it will just quit.&lt;br /&gt;
*ExitMode=Reload... will not save but will reload the screen. &lt;br /&gt;
*ExitMode=AutoReload&lt;br /&gt;
&lt;br /&gt;
To set ExitMode in one of your functions, simply assign it a value from the list above.&lt;br /&gt;
&lt;br /&gt;
====== ScreenIO ExitMode Constants ======&lt;br /&gt;
SaveAndQuit, SelectAndQuit and all the other values above are ScreenIO ExitMode Constants. The ScreenIO ExitMode Constants are set for you in your custom helper library in order to help facilitate the readability of your ScreenIO Code. The values are set with code such as the following, and even inside ScreenIO they&#039;re tested for by name.&lt;br /&gt;
&lt;br /&gt;
  let Quitonly=1&lt;br /&gt;
  let Saveandquit=2&lt;br /&gt;
  let Selectandquit=3&lt;br /&gt;
  let Quitother=4&lt;br /&gt;
  let Asksaveandquit=5&lt;br /&gt;
  let Reload=6&lt;br /&gt;
  let AutoReload=7&lt;br /&gt;
&lt;br /&gt;
=== Working with the ScreenIO Loading Icon ===&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with an Animated Loading Icon that automatically appears whenever a listview takes a long time to load. This tells the user that something is happening, so they know its not just hung.&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything to your screens to use the loading animation. It automatically happens whenever a listview takes more then a couple seconds to load.&lt;br /&gt;
&lt;br /&gt;
==== Changing the Loading Icon ====&lt;br /&gt;
&lt;br /&gt;
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.&lt;br /&gt;
&lt;br /&gt;
If you look in the &amp;quot;clocks&amp;quot; folder that came with ScreenIO, you&#039;ll see three folders: &amp;quot;clock&amp;quot;, &amp;quot;grandfather clock&amp;quot; and &amp;quot;kitchen clock&amp;quot;. ScreenIO ignores all the other folders, and only looks inside the &amp;quot;clock&amp;quot; folder.&lt;br /&gt;
&lt;br /&gt;
To change which clock you want to use, simply delete the contents of the &amp;quot;clock&amp;quot; folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Making your own clock animations ====&lt;br /&gt;
&lt;br /&gt;
Its very simple to make your own clock animations. All you have to do is place a bunch of image files in a folder, depicting the different steps of the animation. They can be either jpg&#039;s or gif&#039;s. You can have as many files as you want, and they can be any resolution you want, but keep in mind that large animations may run slow in network or internet environments. If you intend to run your software over a network share, or over Client Server, you may wish to stick to reasonably sized files. You can get plenty of detail for a loading animation out of a 2k image file.&lt;br /&gt;
&lt;br /&gt;
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn&#039;t have to be square.&lt;br /&gt;
&lt;br /&gt;
ScreenIO reads all the images in the clocks\clock folder and sorts them alphabetically, then plays them in a loop. The timing and size and color of the animation window is controlled via the clock.ini settings file.&lt;br /&gt;
&lt;br /&gt;
===== The clock.ini settings file =====&lt;br /&gt;
&lt;br /&gt;
In your clock folders, you&#039;ll see a clock.ini settings file. Its a very short csv file containing five fields in order. All of the fields are optional. The Clock.ini file itself is optional, in fact. If the file is not found, or any of the values are missing, then default values are used.&lt;br /&gt;
&lt;br /&gt;
The five parameters, and their default values are as follows:&lt;br /&gt;
&lt;br /&gt;
#) Animation Speed (.5) - This is the Animation Speed, in seconds of delay. The default value will update the animation every half second. Use a lower value for a smoother animation, but be careful, if you use too low of a value you can slow down the processing of the listview. This number should be specific to the animation you&#039;re using. If your frames are very different from each other you&#039;ll want a high value like .5 or .6. If the frames are only changed slightly from each other, and you have a lot of them, then you might want the animation to play faster, like .1 or .2. An animation speed of 0 will force it to update as often as possible, which is one frame each time another chunk of data is sent to the listview.&lt;br /&gt;
#) Rows (5) - The size of the animation window in Rows.&lt;br /&gt;
#) Cols (10) - The size of the animation window in Columns.&lt;br /&gt;
#) Color$ (inherited) - The  BR color for the animation window. If present, this parameter is what goes in the &amp;quot;N=&amp;quot; part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.&lt;br /&gt;
#) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.&lt;br /&gt;
&lt;br /&gt;
==== Submitting your clock animations ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve made a nice clock, and you&#039;d like to submit it to be included in future releases of ScreenIO, please zip the entire clocks folder and email it to me at gabriel.bakker@gmail.com. I welcome and encourage your submissions, and I look forward to seeing the beautiful loading clocks that you come up with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) ===&lt;br /&gt;
When using ScreenIO, there are several ways to control the designer with the keyboard. Almost any function can be accessed from the Windows Dropdown Menu, which you can get to from the keyboard by using the Alt key in combination with the underlined letters in the Menu, and with the arrow keys.&lt;br /&gt;
&lt;br /&gt;
You can also use following keyboard shortcuts any time in the ScreenIO Designer.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-V .. Paste Controls&lt;br /&gt;
  Ctrl-X .. Cut Controls&lt;br /&gt;
  Ctrl-C .. Copy Controls&lt;br /&gt;
  Alt-Z ... Undo&lt;br /&gt;
  Alt-R ... Redo&lt;br /&gt;
&lt;br /&gt;
You can use standard keys for Copy, Cut, and Paste in screenio. Copy and Cut act on the current controls and copy them to the clipboard. They are copied to the clipboard in plain text, so its possible to paste them in notepad and then later select them and copy and paste them back into another ScreenIO screen. You can use the clipboard the same way you would expect to use it in any windows program.&lt;br /&gt;
&lt;br /&gt;
Alt-Z and Alt-R Undo and Redo the last operations. You can use them any time in ScreenIO. The only reason its not the standard Ctrl-Z and Ctrl-R is because BR reacts better to Alt-Z and Alt-R.&lt;br /&gt;
&lt;br /&gt;
==== Listview Column Editing Mode ====&lt;br /&gt;
You can use the following keys to reorder the columns in your listview.&lt;br /&gt;
&lt;br /&gt;
  Ctrl-Lf ... Move the column to the left&lt;br /&gt;
  Ctrl-Rt ... Move the column to the right&lt;br /&gt;
&lt;br /&gt;
==== Screen Control Movement Mode ====&lt;br /&gt;
The following controls work in Control Movement Mode Only&lt;br /&gt;
&lt;br /&gt;
  Lf ...... Move the control left&lt;br /&gt;
  Rt ...... Move the control to the right&lt;br /&gt;
  Up ...... Move the control up&lt;br /&gt;
  Dn ...... Move the control down&lt;br /&gt;
  Space ... Make the control Wider&lt;br /&gt;
  BkSp .... Make the control narrower&lt;br /&gt;
  PgDn .... Make the control taller&lt;br /&gt;
  PgUp .... Make the control shorter&lt;br /&gt;
  Enter ... Cycle through the Control Attributes and Movement Mode&lt;br /&gt;
  Del ..... Delete the selected control from the screen&lt;br /&gt;
  Ctrl-S .. Toggle Selection for current control&lt;br /&gt;
  Ctrl-T .. Select All Textboxes&lt;br /&gt;
  Esc ..... Unselect all or exit the current control&lt;br /&gt;
  F6 ...... Draw or Redraw the Movement Grid&lt;br /&gt;
  Ctrl-E .. Make all Left Edges of selected controls match the current control&lt;br /&gt;
  Ctrl-R .. Make all Right Edges of Selected Controls match the current control&lt;br /&gt;
  Ctrl-W .. Make all Widths of selected controls match the current control&lt;br /&gt;
&lt;br /&gt;
===== Selecting Multiple Controls =====&lt;br /&gt;
&lt;br /&gt;
You can use CTRL-S to toggle the selection of the current control, turning it Green, building a group of selected controls. Once you have a bunch of controls selected you can change their attributes or position as a group, instead of having to work with them one at a time.&lt;br /&gt;
&lt;br /&gt;
To select a group of controls, simply click on the controls you want to select one at a time, and press CTRL-S between each click to select them.&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn about control grouping is to try it out. Save your screen and experiment with selecting several controls to see what happens.&lt;br /&gt;
&lt;br /&gt;
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.&lt;br /&gt;
&lt;br /&gt;
If you move any control, the other selected controls will move with you. You can retain the selection outside of control movement mode but you must be in control movement mode in order to change the selection. Outside of control movement mode the only effects that are shared with the group Copy and Cut, and changing properties. If you change any control properties while there is a selected control group, then a message box will appear asking if you would like to copy the changes to all selected controls in the group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on [[#Click_to_Move_Control_Movement|Mouse Movement]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Update Process==&lt;br /&gt;
&lt;br /&gt;
If you used an older version of ScreenIO and updated it to a newer version and you recieved a message from ScreenIO saying that it needs to recompile your helper libraries and update your folder structure, thats because we have recently moved all your ScreenIO Helper Libraries into their own subdirectory, in order to keep from cluttering up your main installation directory as much as possible.&lt;br /&gt;
&lt;br /&gt;
If you do not get this message when updating, don&#039;t worry about it. Chances are you were already running with a newer version of ScreenIO. But if you do get this message, then here is a little more information about what it is and what it means.&lt;br /&gt;
&lt;br /&gt;
Your ScreenIO Helper Libraries have been moved into a new folder called &#039;screenio\&#039;. If you referenced any of these files in your existing code, you may need to update those references. We have generated this brconfig file of substitution statements to aid in this process. To use it simply add &#039;include screenio\screenio.sys&#039; to your brconfig.sys file.&lt;br /&gt;
       &lt;br /&gt;
WARNING: If any of the following substitution statements conflict with one of your file names you will not be able to use them. Carefully inspect these files to ensure they do not conflict with the names of any of your data files. If they do, you will not be able to use the substitution statements because they will affect your data files as well as your program name references. You will have to remove those lines from this file before using this file, and manually fix all the references in your existing code to any programs who&#039;s names conflict with your data files.&lt;br /&gt;
          &lt;br /&gt;
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.&lt;br /&gt;
&lt;br /&gt;
== Recent Changes ==&lt;br /&gt;
Here&#039;s a list of the things recently added to screenio:&lt;br /&gt;
*File Is Locked message much faster&lt;br /&gt;
*Automatically Save a Backup of your Screen&lt;br /&gt;
*Designer made Faster and more Stable, doesn&#039;t query sort order during design time for listviews&lt;br /&gt;
*Improved cursor movement with listviews&lt;br /&gt;
*Fixed a bug in Multiselect Listviews&lt;br /&gt;
*Fixed several bugs in reading Listviews&lt;br /&gt;
*Made it automatically scan and restore the screen in non-gui situations&lt;br /&gt;
*Made PowerSearch properly search for a field from the database. Searching for cu_name will search for all screens that use the customer name field, regardless of where in the screen its used. It will also return the file layout for the customer file.&lt;br /&gt;
&lt;br /&gt;
*Combination Listview/Add/Edit is now possible&lt;br /&gt;
*Generate Screen Wizard&lt;br /&gt;
*Better processing of Listview Read events&lt;br /&gt;
*New Color Picker&lt;br /&gt;
*Better Captions&lt;br /&gt;
*Better Layout for 4:3 monitors&lt;br /&gt;
*ScreenIO Date Processing (has been in ScreenIO for a while)&lt;br /&gt;
*+w, +m and +y for screenIO Date Processing&lt;br /&gt;
*ini file for options&lt;br /&gt;
*Combo Boxes (added to wiki, they were already in ScreenIO)&lt;br /&gt;
*mat ControlSpec$ to get your specs for your controls&lt;br /&gt;
*mat UserData$ on a screen level&lt;br /&gt;
*Default Event Functions that run on every screen&lt;br /&gt;
&lt;br /&gt;
== Future Changes ==&lt;br /&gt;
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you&#039;d like to see and its not already listed here, feel free to add it. I will remove the features from the list as they are implemented in ScreenIO.&lt;br /&gt;
&lt;br /&gt;
=== New Future Change Requests ===&lt;br /&gt;
All currently requested features have been implemented. If you have a feature in mind you&#039;d like to see, feel free to post it here, and also please notify [mailto:gabriel.bakker@gmail.com gabriel.bakker@gmail.com]. When I have finished implementing the feature, i&#039;ll remove it from the list that you make here.&lt;br /&gt;
&lt;br /&gt;
*Add your Feature&lt;br /&gt;
*Requests Here&lt;br /&gt;
&lt;br /&gt;
=== Completed Future Change Requests ===&lt;br /&gt;
&lt;br /&gt;
The following list of change requests has been completed.&lt;br /&gt;
&lt;br /&gt;
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.&lt;br /&gt;
*Non-Data Screens - the ability to call fnfm with your own mat F$ and mat F and have it work with your passed in data instead of automatically reading and writing from your data file.&lt;br /&gt;
*True Numeric Fields in Listviews supported with BR 4.2&lt;br /&gt;
*Numeric Fields on regular Text Box Controls&lt;br /&gt;
*Mainloop event to support custom keys&lt;br /&gt;
*Error Handling Improvement&lt;br /&gt;
*Animated &amp;quot;Loading Icon&amp;quot; for populating Large Listviews&lt;br /&gt;
*Group Movement/Alignment of controls&lt;br /&gt;
*Copy and Paste of Controls from one screen to another screen&lt;br /&gt;
*Group Copy and Paste of Controls&lt;br /&gt;
*ScreenIO Helper Libraries in a special folder&lt;br /&gt;
*ScreenIO itself in a special folder&lt;br /&gt;
*Add the &amp;quot;-d&amp;quot; option to the ScreenIO Screenfld file to keep it from growing huge after some time&lt;br /&gt;
*Additional Field level Properties in Screenflds for Programmers to use for things&lt;br /&gt;
*Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well&lt;br /&gt;
*Advanced Filtering of a Listview - using the proper index to make it run faster&lt;br /&gt;
&lt;br /&gt;
[[Category:Utilities_Third_Party]]&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10691</id>
		<title>Filter</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10691"/>
		<updated>2015-11-03T16:15:52Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Note */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Grid and list &#039;&#039;&#039;filter&#039;&#039;&#039; search fields are available as of BR! [[4.3]] for [[grids and lists]].&lt;br /&gt;
&lt;br /&gt;
A new field type is defined (similar to [[SEARCH]]):&lt;br /&gt;
&lt;br /&gt;
[[image:Filter.png|900px]]&lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;nn,nn,15/FILTER 10,leading-attributes,row,col,grid column to search [, filter-type] [, CASE]&amp;quot;: string-value&lt;br /&gt;
&lt;br /&gt;
For example: &lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;4,50,15/FILTER 10,,10,10,2,ALL&amp;quot;: Findfield$&lt;br /&gt;
&lt;br /&gt;
This example combines a filter box (which will search everything in the list) and the rinput fields for a list selection:&lt;br /&gt;
&lt;br /&gt;
 rinput fields &amp;quot;4,8,78/FILTER 30,/w:w,5,6,Fullrow,all;5,6,list 21/80,rowsub,selone&amp;quot;: foundvar$,selection&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nn and nn&#039;&#039;&#039; are the row and column to position the field on the screen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Size/&#039;&#039;&#039; and &#039;&#039;&#039;Characters&#039;&#039;&#039; signifies how large the filter field will be in columns, and how many characters can be entered into it. In the example, &#039;&#039;&#039;15/ and 10&#039;&#039;&#039; provide a 15 column field where the operator can enter 10 characters. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Leading attributes&#039;&#039;&#039; can be any attributes desired (optional). &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Row and col&#039;&#039;&#039; are the starting row and column of the grid or list you wish to search.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grid column to search&#039;&#039;&#039; is the number of the grid column the filter will test against. FULLROW can be used here to searchall the columns in each row. &lt;br /&gt;
&lt;br /&gt;
====Filter Types====&lt;br /&gt;
*LEADING - Filter searching is done left justified using only leading characters (default).&lt;br /&gt;
*WORD - Each word is leading matched.&lt;br /&gt;
*ALL - The entire string is searched for a match (similar to [[POS]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CASE&#039;&#039;&#039; may optionally be used to make all searching case sensitive. Case insensitivity is the default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;String-value&#039;&#039;&#039; is the variable name which will apply to whatever the operator enters into the field for searching. &lt;br /&gt;
&lt;br /&gt;
For both FILTER and [[Srch]], the up and down arrows now affect only the selection bar in the grid/list being presented.&lt;br /&gt;
&lt;br /&gt;
====Note====&lt;br /&gt;
&lt;br /&gt;
* MASK can be used to query the Filter display, with a value of 1.&lt;br /&gt;
&lt;br /&gt;
====See Also====&lt;br /&gt;
&lt;br /&gt;
* [[Filter_Delimiters]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Widget]]&lt;br /&gt;
[[Category:Grid and List]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Grid_and_List&amp;diff=10690</id>
		<title>Grid and List</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Grid_and_List&amp;diff=10690"/>
		<updated>2015-11-03T16:14:53Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Parameters */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Grid&#039;&#039;&#039; and &#039;&#039;&#039;List&#039;&#039;&#039; (a.k.a. &#039;&#039;&#039;ListView&#039;&#039;&#039;) are [[Two dimensional controls]], which means that they contain rows and columns. GRIDs are normally used for data entry, while LISTs are used only for selection. In Business Rules, outputting to these controls is done with [[Print Fields]] and inputting from them is done with [[Input Fields]]. Each field specification pertains to one [[Control]]. However, a single FIELD specification can pertain to a parenthesized group of arrays. When using Grids and Lists, first the header must be populated, and then the data within the rows. &lt;br /&gt;
&lt;br /&gt;
The [[INPUT FIELDS]] specification states Grid or List as the field type. The display area is specified in terms of rows and columns separated by a slash. The following parameter, instead of being leading field attributes, is a secondary keyword indicating the type (CNT/SUB/CELL/ROWCNT/ROWSUB/ROW) of output or input operation to be performed. The next parameter further qualifies the IO operation (CHG/SEL/ALL/CUR/NEXT). Normally this trailing attribute is an [[FKEY]] value which is shifted right one parameter in this context. &lt;br /&gt;
&lt;br /&gt;
It is useful to work with [[2D Controls]] in terms of rows versus cells, particularly when the columns are dissimilar. A complete set of row oriented parameters are provided for that purpose. Output operations support the mass populating of 2D controls row by row. And input operations can be row oriented as well. The keywords associated with row processing are R, ROWCNT, ROWSUB, and ROW. &lt;br /&gt;
&lt;br /&gt;
RINPUT does not work with 2D controls because the output statements are somewhat different from the input statements. The output consists of setting up the columns, including providing the column headings, and populating the control with data. The input consists of identifying what has changed in a manner that enables selective data retrieval and corresponding file updating. &lt;br /&gt;
&lt;br /&gt;
If the user clicks on a column heading the GRID or LIST will be sorted on that column. Sorting is done in terms of rows. Such sorting of these controls has no affect on the BR program. The information returned to BR will be as though no sorting were performed. If a control&#039;s population is increased by populating with the plus (+) flag, the control will be resequenced back to its original order before the data is added. One way a program can restore the original displayed order of a GRID or LIST is to populate it incrementally (+) with no data. As of version 4.1 and higher, if a GRID input is attempted on a protected field, BR issues a Bell. &lt;br /&gt;
&lt;br /&gt;
Shift+PgUp and Shift+PgDn selects within a List/Grid. &lt;br /&gt;
&lt;br /&gt;
Grids and lists are compatible with the [[FILTER]] field, which works like a search bar. &lt;br /&gt;
&lt;br /&gt;
In GRIDs and LISTs only, string arrays may be used to process numeric values. BR automatically performs [[VAL]] and [[STR]] conversions as needed.  If string data is passed to a numeric field type such as N or DATE then it is automatically converted to numeric form for internal processing (4.2).&lt;br /&gt;
&lt;br /&gt;
As of Business Rules! versions [[4.3]]+, arrays are automatically resized when receiving data from 2D INPUT operations. This also applies to grouped arrays. Automatic resizing only applies to one dimensional arrays and does not occur when INPUTing into two dimensional arrays. For example, where all arrays are one dimensional and may have the incorrect number of elements:&lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, ROW, ALL&amp;quot;&amp;amp;nbsp;: ( MAT Array1$,&amp;lt;span style=&amp;quot;font-family: monospace;&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;MAT Array2$, MAT Array3, MAT Array4, MAT Array5$ )  &lt;br /&gt;
&lt;br /&gt;
====FKey Processing====&lt;br /&gt;
&lt;br /&gt;
An [[FKey]] value can be associated with a LIST or GRID control by specifying the FKey number during either output or input operations. Once an Fkey value is specified, the control retains the setting until it is reset. An FKey value can be cleared by specifying an Fkey value of minus one (-1). &lt;br /&gt;
&lt;br /&gt;
When a LIST or GRID has an FKey value set processing is dependent on whether or not the 2D control is being processed by an INPUT FIELDS statement: &lt;br /&gt;
&lt;br /&gt;
*Displayed but inactive- Single clicking any cell produces the FKey interrupt. &lt;br /&gt;
*Active (participating in Input Fields)- Double clicking any cell produces an FKey completion.&lt;br /&gt;
&lt;br /&gt;
Formerly, [[CURROW]] and [[CURCOL]] represented the character position where the cursor was when FIELDS processing is completed. This is still true except when the most recent field processed is a [[2D control]]. &lt;br /&gt;
&lt;br /&gt;
When FIELDS processing ends and control is returned to the program while the &#039;current&#039; control is of type LIST or GRID, CURROW and CURCOL are set to the current cell row and column within the 2D control instead of the character position relative to the window.&lt;br /&gt;
&lt;br /&gt;
====GRID CURSOR MOVEMENT====&lt;br /&gt;
When field + or - is keyed BR Always returns fkey values of 114 or 115 in&lt;br /&gt;
both navigation and edit mode and for any type of data. (This assumes the X&lt;br /&gt;
attribute or some other attribute returns control to the program.)&lt;br /&gt;
&lt;br /&gt;
In edit mode, Field +/- always forces the signing of a numeric field, &lt;br /&gt;
whether or not the field type is PIC.&lt;br /&gt;
&lt;br /&gt;
In edit mode, field plus or minus right truncates any character or numeric &lt;br /&gt;
data before exiting the field.&lt;br /&gt;
&lt;br /&gt;
A new Config statement is defined to help with grid cursor movement: &lt;br /&gt;
&lt;br /&gt;
 GRID_CURSOR_MOVE  DOWN | RIGHT | NONE | DEFAULT&lt;br /&gt;
&lt;br /&gt;
This determines the field cursor position after keying Enter or &lt;br /&gt;
Field +/-. Both navigation and edit mode produce the same resulting cursor &lt;br /&gt;
position.&lt;br /&gt;
&lt;br /&gt;
Default Enter and Field +/- cursor movement are unchanged. Field plus &lt;br /&gt;
or minus perform a down arrow operation, and Enter defaults to NONE. &lt;br /&gt;
GRID_CURSOR_MOVE overrides both of these.&lt;br /&gt;
&lt;br /&gt;
====Restoring a User Sorted 2D Control====&lt;br /&gt;
&lt;br /&gt;
In versions 4.3 and higher the syntax for sorting a listview is: &lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column number }&lt;br /&gt;
&lt;br /&gt;
This has been extended to allow a numeric array instead of a scalar. If an array is given, it is assumed to be in the same format that SORT_ORDER returns. The new format is: &lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column-number | numeric-array }&lt;br /&gt;
&lt;br /&gt;
Where the numeric-array has one element for each column left to right. BR will resort the columns in the requested order. &lt;br /&gt;
&lt;br /&gt;
The numeric array values indicating the order of column sorting to be performed do not need to exactly match the standard format. e.g Fractions are allowed, the values can fall within any range, and there does not need to be trailing zero elements for unsorted columns. &lt;br /&gt;
&lt;br /&gt;
==== A multi column LISTview  ====&lt;br /&gt;
&lt;br /&gt;
 01000 PRINT FIELDS &amp;quot;10,20,LIST 10/80,HEADERS,[HDRS][,fkey]&amp;quot;: (MAT HEADINGS$,MAT WIDTHS, MAT FORMS$)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Widths are expressed in character positions.&lt;br /&gt;
&lt;br /&gt;
The [HDRS] notation refers to an optional CONFIG ATTRIBUTE HDRS specification for setting the appearance of the header row. In this case the  brackets [] are required and the term HDRS may be any bracketed attribute name. &lt;br /&gt;
&lt;br /&gt;
If a function key value (e.g. 1520) is given then when the control is not active, it may be clicked to trigger the specified interrupt similar to any other hot control. A function key interrupt is also triggered by double clicking during an Input operation. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;MAT HEADINGS$&#039;&#039;&#039; &lt;br /&gt;
| Specifies the titles that will appear at the top of each column in the List or Grid. The format of this row may be specified by an optional parameter following HEADERS in the above example.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;MAT WIDTHS&#039;&#039;&#039; &lt;br /&gt;
| Specifies the number of characters in each column. For example if four columns are specified and the widths are given as 10, 15, 10 and 5, then the 2D control occupies 40 character positions (plus a little for the column separators) irrespective of the number of columns specified for the display area. If needed, scroll bars are used to display wider controls within the displayed area.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;MAT FORMS$&#039;&#039;&#039; &lt;br /&gt;
| Specifies the display characteristics of each column such as &amp;quot;C 12&amp;quot; or &amp;quot;PIC(z,zzz,zz#.##-)&amp;quot;. A &amp;quot;P&amp;quot; following the display parameter will cause the field to be protected and no data entry will be allowed in GRID mode.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; The field form array elements may also include a trailing comma followed by field attributes (e.g. color) that pertain to the column. &lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;10,20,LIST 10/80, = [,fkey]&amp;quot;: (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
In this example, the fourth element of the HEADERS FIELD_FORM$ array (above) could specify rounding of WEIGHT to two decimal places. If an fkey value is specified, then double-clicking (or single clicking if S is specified) a cell will generate the specified fkey interrupt.&lt;br /&gt;
&lt;br /&gt;
==== Reading a Listview or Grid  ====&lt;br /&gt;
When using INPUT FIELDS to read from a 2D control, the leading attributes specification states the type of read operation and the trailing attributes specification is the type of cell or row selection to be performed. The third parameter can optionally specify NOWAIT or an FKEY value. If it is an FKEY value, it signifies that an FKEY event should be triggered when, in navigation mode, a selection is made by double clicking or pressing the Enter key.&lt;br /&gt;
 &lt;br /&gt;
===== Syntax  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Grid.png|950px]]&lt;br /&gt;
&lt;br /&gt;
=====Parameters=====&lt;br /&gt;
Quotation marks must surround the specifications, and individual parts must be separated by commas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Row&#039;&#039;&#039; and &#039;&#039;&#039;Column&#039;&#039;&#039; specify the space where the grid or list begins.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;List&#039;&#039;&#039; or &#039;&#039;&#039;Grid&#039;&#039;&#039;, followed by rows and columns separated by a slash determine how big the list or grid is going to be. The main difference between a list and grid is that lists are for selection only while information can be added to grids directly. &lt;br /&gt;
&lt;br /&gt;
The following &#039;&#039;&#039;Read Types&#039;&#039;&#039; are valid for both grids and lists:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;RowCnt&#039;&#039;&#039; &lt;br /&gt;
| The number of rows specified.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;RowSub&#039;&#039;&#039; &lt;br /&gt;
| The subscripts of the specified rows.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Row&#039;&#039;&#039; &lt;br /&gt;
| Read all cells in each specified row.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Colcnt&#039;&#039;&#039; &lt;br /&gt;
|The number of columns established by the header arrays. e.g. INPUT FIELDS &amp;quot;row,col,LIST rows/cols, COLCNT, ALL&amp;quot; : numeric-variable&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Sort_Order&#039;&#039;&#039; &lt;br /&gt;
|(4.3+) Provides a value of zero for each unsorted column and gives the ascending sequence of column sorts that have occurred. If a column has been reversed (double sorted) it&#039;s value will be negative. The selection typed used must be ALL. For example: INPUT FIELDS &amp;quot;row,col,GRID rows/cols, SORT_ORDER, ALL&amp;quot; : Mat NumArray, with the following history of sorting a four column GRID:&lt;br /&gt;
 column 1 (descending most recent)&lt;br /&gt;
 column 2 (ascending first sorted)&lt;br /&gt;
 column 3 (not sorted)&lt;br /&gt;
 column 4 (sorted ascending)&lt;br /&gt;
&lt;br /&gt;
SORT_ORDER would return-&lt;br /&gt;
 array(1) -&amp;gt;  -1&lt;br /&gt;
 array(2) -&amp;gt;   3&lt;br /&gt;
 array(3) -&amp;gt;   0&lt;br /&gt;
 array(4) -&amp;gt;   2&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;HEADERS&#039;&#039;&#039;&lt;br /&gt;
|(As of 4.30) The read operation returns the original PRINT FIELDS HEADER values. For example:  INPUT FIELDS &amp;quot;row,col,LIST rows/cols, HEADERS,,NOWAIT&amp;quot; : (MAT HEADINGS$,MAT WIDTHS, MAT FORMS$) The selection typed used must be ALL.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;MASK&#039;&#039;&#039;&lt;br /&gt;
|(As of 4.30) MASK can be used with Grids and Lists. As a READ type, this reads the display mask setting, including listviews that have been displayed according to a [[filter]] or filterbox. For example: INPUT FIELDS &amp;quot;row,col,LIST rows/cols,MASK [,NOWAIT]&amp;quot; : mask_array. The mask array affects only the user presentation and not the data. Use RANGE processing or the CHG selection type to selectively read from a 2D control.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These Read Types are valid for Grids only:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Cnt&#039;&#039;&#039; &lt;br /&gt;
| Specify the number of cells specified (see selection types below).&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Sub&#039;&#039;&#039; &lt;br /&gt;
| Read the Cell Subscript Values (see example below).&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Cell&#039;&#039;&#039; &lt;br /&gt;
| Read each cell specified.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For the &amp;quot;Sel-type&amp;quot; parameter, the following selection types are valid for both grids and lists:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Sel&#039;&#039;&#039; &lt;br /&gt;
| Read one or more selected items.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;SelOne&#039;&#039;&#039; &lt;br /&gt;
| Select only one item.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;All&#039;&#039;&#039; &lt;br /&gt;
| Read all items in the control (except headings).&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Cur&#039;&#039;&#039; &lt;br /&gt;
| Current cell or row number.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Next (4.2+)&#039;&#039;&#039; &lt;br /&gt;
| The cell the cursor is going to next if the user moved it using an arrow or a mouse click.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Range&#039;&#039;&#039;&lt;br /&gt;
|Specifies which portion of a 2D control is to be input. (As of 4.3) [[#Range Input|See Below]].&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Cell_Range&#039;&#039;&#039;&lt;br /&gt;
|A special type of output range. (As of 4.3) [[#Range Input|See Below]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This Selection Type is valid for Grids only:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Chg&#039;&#039;&#039; &lt;br /&gt;
| All items changed since the last &#039;=&#039; populate or the last CHG retrieval of cell/row contents.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Read Qualifier&#039;&#039;&#039; is an optional parameter to help the read. As of 4.3 it can be [[DISPLAYED_ORDER]]. #[[PIC]] or #[[FMT]] could be used. #PIC and #FMT allow numeric data from a string to be used. For example: &#039;&#039;&#039;DISPLAYED_ORDER&#039;&#039;&#039; Indicates that the read operation is to not restore the data into it&#039;s original order before returning the results to the program (as of version 4.30). This reads the original row subscripts for all rows - in their present order - and only works with the ALL selection type.&lt;br /&gt;
&lt;br /&gt;
GRIDLINES makes LIST controls look like GRIDs with respect to the display of data (column and row separators).&lt;br /&gt;
 PRINT FIELDS &amp;quot;10,20,LIST 10/80,GRIDLINES&amp;quot;: 1 | 0 (on or off)&lt;br /&gt;
&lt;br /&gt;
The leading attribute values &amp;quot;^select&amp;quot; or &amp;quot;^deselect&amp;quot; may be specified to allow the pre-selection of GRID / LIST Elements: &lt;br /&gt;
 PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,^select ATTR&amp;quot;: (mat start, mat end, mat attr$)&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Fkey&#039;&#039;&#039; and &#039;&#039;&#039;Nowait&#039;&#039;&#039; parameters are optional. FKEY means that an FKEY event should be triggered when a selection is made by double clicking or pressing the Enter key, in navigation mode. Nowait simply means that it does not wait for user input.&lt;br /&gt;
&lt;br /&gt;
Following the ending quotation mark, a colon precedes the name of the I/O List.&lt;br /&gt;
&lt;br /&gt;
====DISPLAYED ORDER &#039;&#039;&#039;Read Qualifier&#039;&#039;&#039;==== &lt;br /&gt;
&lt;br /&gt;
As of 4.30, [[DISPLAYED ORDER]] - indicates that the read operation is to not restore the data into it&#039;s original order before returning the results to the program, for example:&lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, ROWSUB, ALL, DISPLAYED_ORDER, NOWAIT&amp;quot;: numeric-array &lt;br /&gt;
&lt;br /&gt;
This reads the original row subscripts for all rows in their present order. This qualifier works only with the ALL selection type. It may be used in conjunction with other qualifiers such as FKEY.&lt;br /&gt;
&lt;br /&gt;
==== Examples  ====&lt;br /&gt;
&lt;br /&gt;
===== LIST  =====&lt;br /&gt;
&lt;br /&gt;
 00210 INPUT FIELDS &amp;quot;10,20,LIST 10/80,ROWCNT,SEL,FKEY&amp;quot;: avail_rows&amp;amp;nbsp;! selected row cnt&lt;br /&gt;
 00220&amp;amp;nbsp;! next INPUT operation does not wait for operator&lt;br /&gt;
 00230 MAT subscr(avail_rows)         &amp;amp;nbsp;! redimension with number of selected rows&lt;br /&gt;
 00240 INPUT FIELDS &amp;quot;10,20,LIST 10/80,ROWSUB,SEL,NOWAIT&amp;quot;: MAT subscr&amp;amp;nbsp;! read subscripts&lt;br /&gt;
&lt;br /&gt;
===== Uniform GRID  =====&lt;br /&gt;
Contains one data array and multiple columns&lt;br /&gt;
&lt;br /&gt;
 00210 INPUT FIELDS &amp;quot;10,20,GRID 10/80,CNT,CHG&amp;quot;: cells     &amp;amp;nbsp;! # of changed cells&lt;br /&gt;
 00220 MAT subscr(cells)                                        &amp;amp;nbsp;! redimension&lt;br /&gt;
 00230 INPUT FIELDS &amp;quot;10,20,GRID 10/80,SUB,CHG,NOWAIT&amp;quot;: MAT subscr&amp;amp;nbsp;! read subscripts&lt;br /&gt;
 00240 MAT data$(cells)                                         &amp;amp;nbsp;! redimension&lt;br /&gt;
 00250 INPUT FIELDS &amp;quot;10,20,GRID 10/80,CELL,CHG,NOWAIT&amp;quot;: MAT data$&amp;amp;nbsp;! read changes&lt;br /&gt;
&lt;br /&gt;
===== Row Oriented GRID  =====&lt;br /&gt;
 00210 INPUT FIELDS &amp;quot;10,20,GRID 10/80,ROWCNT,CHG&amp;quot;: rows  &amp;amp;nbsp;! # of changed rows&lt;br /&gt;
 00220 MAT subscr(rows)                                  &amp;amp;nbsp;! redimension&lt;br /&gt;
 00230 INPUT FIELDS &amp;quot;10,20,GRID 10/80,ROWSUB,CHG,NOWAIT&amp;quot;: MAT subscr&amp;amp;nbsp;! read subscripts&lt;br /&gt;
 00240 MAT NAME$(rows)&amp;amp;nbsp;: MAT CITY$(rows)&amp;amp;nbsp;: MAT AGE(rows)&amp;amp;nbsp;: MAT WEIGHT(rows)&amp;amp;nbsp;! redimension&lt;br /&gt;
 00250 INPUT FIELDS &amp;quot;10,20,GRID 10/80,ROW,CHG,NOWAIT&amp;quot;: (MAT NAME$, MAT CITY$,MAT AGE, MAT WEIGHT)  &amp;amp;nbsp;! read changed rows&lt;br /&gt;
&lt;br /&gt;
This brings us to the question of what is to be done with the information after it has been read. If it is to be stored in a file, then we should have included a hidden column with master file record numbers of the data in each row. This would support looping through the input array and rewriting the changed data. &lt;br /&gt;
&lt;br /&gt;
While LIST subscripts are expressed in terms of rows, GRID subscripts may be either. In a four column five row GRID, the cell at row three column two has a subscript of ten.&lt;br /&gt;
&lt;br /&gt;
==== Cell Subscript Values of a 5 x 4 GRID  ====&lt;br /&gt;
&lt;br /&gt;
 1   2   3   4&lt;br /&gt;
 5   6   7   8&lt;br /&gt;
 9  10  11  12&lt;br /&gt;
 13 14  15  16&lt;br /&gt;
 17 18  19  20&lt;br /&gt;
&lt;br /&gt;
==== Sample Program====&lt;br /&gt;
The following example shows use of LIST and GRID controls. There are seven parts in this program. &lt;br /&gt;
&lt;br /&gt;
The first part creates a LIST with 2 columns and 3 rows. On lines 300 - 500, column headings, widths, and form specifications are assigned to the corresponding matrices. Lines 600 and 700 place data into the matrices to be printed in the LIST. The HEADERS operation on line 800 sets the column headings, widths and form specs. Line 900 populates the LIST by row, which is the default. &lt;br /&gt;
&lt;br /&gt;
 00100 dim HEADINGS$(2), WIDTHS(2), FORMS$(2), NAMES$(3)*28, CITIES$(3)*18, DATA$(1)*80, SUBSCR(1)&lt;br /&gt;
 00200 print NEWPAGE&lt;br /&gt;
 00300 let HEADINGS$(1)=&amp;quot;Name&amp;quot;: let HEADINGS$(2)=&amp;quot;City&amp;quot;&lt;br /&gt;
 00400 let WIDTHS(1)=30&amp;amp;nbsp;: let WIDTHS(2)=20&lt;br /&gt;
 00500 let FORMS$(1)=&amp;quot;CC 28&amp;quot;&amp;amp;nbsp;: let FORMS$(2)=&amp;quot;CC 18&amp;quot;&lt;br /&gt;
 00600 let NAMES$(1)=&amp;quot;Stalin&amp;quot;&amp;amp;nbsp;: let NAMES$(2)=&amp;quot;Napoleon&amp;quot;&amp;amp;nbsp;: let NAMES$(3)=&amp;quot;Roosevelt&amp;quot;&lt;br /&gt;
 00700 let CITIES$(1)=&amp;quot;Moscow&amp;quot;&amp;amp;nbsp;: let CITIES$(2)=&amp;quot;Paris&amp;quot;&amp;amp;nbsp;: let CITIES$(3)=&amp;quot;Washington&amp;quot;&lt;br /&gt;
 00800 print fields &amp;quot;1,1,list 8/60,headers&amp;quot;: (MAT HEADINGS$,MAT WIDTHS,MAT FORMS$)&lt;br /&gt;
 00900 print fields &amp;quot;1,1,list 8/60,=R&amp;quot;: (MAT NAMES$,MAT CITIES$)&lt;br /&gt;
 01000 print fields &amp;quot;9,1,C 50&amp;quot;&amp;amp;nbsp;: &amp;quot;Press enter to insert at the end of list&amp;quot;&lt;br /&gt;
 01100 let KSTAT$(1)&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output1.jpg]] &lt;br /&gt;
&lt;br /&gt;
The second part of the program demonstrates the use of the primary flag +, which adds to the end of any previously populated data. Line 01200 redimensions matrices NAMES$ and CITIES$ to allow room for one extra item in each of them. Line 01300 places new data into the matrices to be printed in the LIST.&amp;lt;br&amp;gt; Line 01400 adds the new data to the LIST. &lt;br /&gt;
&lt;br /&gt;
 01200 mat NAMES$(UDIM(NAMES$)+1)&amp;amp;nbsp;: mat CITIES$(UDIM(CITIES$)+1)&lt;br /&gt;
 01300 let NAMES$(4)=&amp;quot;Churchill&amp;quot;&amp;amp;nbsp;: let CITIES$(4)=&amp;quot;London&amp;quot;&lt;br /&gt;
 01400 print fields &amp;quot;1,1,list 8/60,+&amp;quot;: (MAT NAMES$(4:4),MAT CITIES$(4:4))&lt;br /&gt;
 01500 print fields &amp;quot;9,1,C 50&amp;quot;&amp;amp;nbsp;: &amp;quot;Select rows to be read into a matrix&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output2.jpg]] &lt;br /&gt;
&lt;br /&gt;
The third part of the program demonstrates use of read types ROWSUB and ROWCNT and selection type SEL. Line 1600 inputs the number of selected rows into AVAIL_ROWS. The user may select rows using the mouse or the keyboard and SHIFT and CTRL keys. Line 1700 redimensions matrix SUBSCR to the number of selected rows. Line 1800 inputs the subscripts of the selected rows into matrix SUBSCR. Line 1900 performs a HEADERS operation for a new LIST using the same matrices as were used in the previous LIST. Line 2000 populates the first row of the new LIST with the data from the first selected row from the previous LIST using the primary flag =. If user selects more than one row, then lines 2100 - 2500 add the data from the selected rows using the primary flag +. &lt;br /&gt;
&lt;br /&gt;
 01600 input fields &amp;quot;1,1,list 8/60,ROWCNT,SEL&amp;quot;: AVAIL_ROWS&lt;br /&gt;
 01700 mat SUBSCR(AVAIL_ROWS)&lt;br /&gt;
 01800 input fields &amp;quot;1,1,list 8/60,rowsub,sel,nowait&amp;quot;: MAT SUBSCR&lt;br /&gt;
 01900 print fields &amp;quot;12,1,list 8/60,headers&amp;quot;: (MAT HEADINGS$,MAT WIDTHS,MAT FORMS$)&lt;br /&gt;
 02000 print fields &amp;quot;12,1,list 8/60,=&amp;quot;: (MAT NAMES$(SUBSCR(1):SUBSCR(1)),MAT CITIES$(SUBSCR(1):SUBSCR(1)))&lt;br /&gt;
 02100 if UDIM(SUBSCR) &amp;amp;gt; 1 then&lt;br /&gt;
 02200   for I = 2 to UDIM(SUBSCR)&lt;br /&gt;
 02300     print fields &amp;quot;12,1,list 8/60,+&amp;quot;: ( MAT NAMES$(SUBSCR(I):SUBSCR(I)),MAT CITIES$(SUBSCR(I):SUBSCR(I)))&lt;br /&gt;
 02400   next I&lt;br /&gt;
 02500 end if&lt;br /&gt;
 02600 print fields &amp;quot;9,1,C 50&amp;quot;&amp;amp;nbsp;: &amp;quot;Press enter to insert at beginning of list&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output3.jpg]] &lt;br /&gt;
&lt;br /&gt;
The fourth part of the program demonstrates the use of the primary flag -, which inserts in the beginning of any previously populated data. Line 2800 redimensions matrices NAMES$ and CITIES$ to allow room for one extra item in each of them. Line 2900 places new data into the matrices to be printed in the LIST. Line 3000 adds the new data to the beginning of the LIST ahead of previously populated data. &lt;br /&gt;
&lt;br /&gt;
 02700 let KSTAT$(1)&lt;br /&gt;
 02800 mat NAMES$(UDIM(NAMES$)+1): mat CITIES$(UDIM(CITIES$)+1)&lt;br /&gt;
 02900 let NAMES$(5)=&amp;quot;Castro&amp;quot;&amp;amp;nbsp;:! let CITIES$(5)=&amp;quot;Havana&amp;quot;&lt;br /&gt;
 03000 print fields &amp;quot;1,1,list 8/60,-&amp;quot;: (MAT NAMES$(5:5),MAT CITIES$(5:5))&lt;br /&gt;
 03100 print fields &amp;quot;9,1,C 60&amp;quot;&amp;amp;nbsp;: &amp;quot;Press enter to populate list by column&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output4.jpg]] &lt;br /&gt;
&lt;br /&gt;
The fifth part of the program, more specifically, Line 3300, demonstrates the use of the secondary flag C to populate the LIST by column. The primary flag = is also used in order to replace any previously populated data. &lt;br /&gt;
&lt;br /&gt;
 03200 let KSTAT$(1)&lt;br /&gt;
 03300 print fields &amp;quot;1,1,list 8/60,=C&amp;quot;: (MAT NAMES$,MAT CITIES$)&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output5.jpg]] &lt;br /&gt;
&lt;br /&gt;
The sixth part of the program creates a GRID. The HEADERS operation on line 3600 uses the same HEADINGS$, WIDTHS, and FORMS$ as the previously constructed LISTs. Line 3700 sets CURFLD to be on the sixth cell of the GRID (this is discussed in the next section). Line 3800 populates the GRID. The user may change the contents of the cells. &lt;br /&gt;
&lt;br /&gt;
 03400 print fields &amp;quot;23,1,C 50&amp;quot;&amp;amp;nbsp;: &amp;quot;Press enter to continue&amp;quot;: let KSTAT$(1)&lt;br /&gt;
 03500 print NEWPAGE&lt;br /&gt;
 03600 print fields &amp;quot;1,1,grid 8/60,headers&amp;quot;: (MAT HEADINGS$,MAT WIDTHS,MAT FORMS$)&lt;br /&gt;
 03700 let CURFLD (1,6)&lt;br /&gt;
 03800 print fields &amp;quot;1,1,grid 8/60,=&amp;quot;: (MAT NAMES$,MAT CITIES$)&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output6.jpg]] &lt;br /&gt;
&lt;br /&gt;
The seventh part of the program demonstrates the use of read types CNT, CELL, and SUB and selection type CHG. Line 3900 counts the number of changed cells and inputs that number into variable CELLS. Line 4000 redimensions the matrix SUBSCR to the number of changed cells. Line 4100 inputs the changed cells into SUBSCR. Line 4200 redimensions the matrix DATA$.  Line 4300 inputs the subscripts of the changed cells into matrix DATA$. Line 4400 prints DATA$. &lt;br /&gt;
&lt;br /&gt;
 03900 input fields &amp;quot;1,1,grid 8/60,cnt,chg&amp;quot;: CELLS&lt;br /&gt;
 04000 mat SUBSCR(CELLS)&lt;br /&gt;
 04100 input fields &amp;quot;1,1,grid 8/60,sub,chg,nowait&amp;quot;: MAT SUBSCR&lt;br /&gt;
 04200 mat DATA$(CELLS)&lt;br /&gt;
 04300 input fields &amp;quot;1,1,grid 8/60,cell,chg,nowait&amp;quot;: MAT DATA$&lt;br /&gt;
 04400 print MAT DATA$&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output6b.jpg]]&lt;br /&gt;
&lt;br /&gt;
===== Output of line 04400  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output7.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Displaying a List or Grid (Output Operations) ===&lt;br /&gt;
[[file:Grid2.png|900px]]&lt;br /&gt;
&lt;br /&gt;
To display a listview or a grid, you must set the headers first, using a special PRINT FIELDS operation.&lt;br /&gt;
&lt;br /&gt;
====HEADERS====&lt;br /&gt;
The HEADERS operation sets the column headings and widths. The corresponding input/output list value must be a parenthesized group of three arrays, for example: &lt;br /&gt;
&lt;br /&gt;
 00250 PRINT FIELDS &amp;quot;10,20,LIST 10/80,HEADERS&amp;quot;: (MAT HEADINGS$, MAT WIDTHS, MAT FIELD_FORMS$)&lt;br /&gt;
      - or -&lt;br /&gt;
 00250 PRINT FIELDS &amp;quot;10,20,GRID 10/80,HEADERS,[hdrs],1520&amp;quot;: (MAT HEADINGS$, MAT WIDTHS,MAT FIELD_FORMS$)&lt;br /&gt;
&lt;br /&gt;
The [hdrs] notation refers to an optional CONFIG ATTRIBUTE [HDRS] specification for setting the appearance of the header row. In this case the [] brackets are required. &lt;br /&gt;
&lt;br /&gt;
If a function key value (e.g. 1520) is given then when the control is not active, it may be clicked to trigger the specified interrupt similar to any other hot control. A function key interrupt is also triggered by double clicking during an Input operation. &lt;br /&gt;
&lt;br /&gt;
MAT HEADINGS$ Contains the column titles that will be displayed at the top of each column. The font, color and shading of these titles can be set through the [HDRS] or similar substitution attribute. &lt;br /&gt;
&lt;br /&gt;
MAT WIDTHS specifies DISPLAYED Column Widths and is expressed as the number of character positions occupied by each column. Scrollbars are provided as needed to honor overall control size specified in the FIELDS specification. &lt;br /&gt;
&lt;br /&gt;
For example, if four columns are specified and the widths are given as 10, 15, 10 and 5, then the 2D control occupies 40 character positions (plus a little for the column separators) irrespective of the number of columns specified for the display area. If needed, scroll bars are used to display wider controls within the displayed area. &lt;br /&gt;
&lt;br /&gt;
Displayed widths of zero characters are allowed. This enables the use of hidden columns for storing things like record numbers and record keys. &lt;br /&gt;
&lt;br /&gt;
MAT FIELD_FORMS$ provides the BR FORM for each column. e.g. C 15 stipulates a maximum field capacity of 15. The actual displayed length is a function of the grid size and the column relative width. &lt;br /&gt;
&lt;br /&gt;
The field form array elements may also include a comma followed by leading field attributes (e.g. color) pertaining to the column.  &lt;br /&gt;
&lt;br /&gt;
The number of columns must be set with HEADERS prior to Populating a control (loading data into it).&lt;br /&gt;
&lt;br /&gt;
====MASKing====&lt;br /&gt;
&lt;br /&gt;
As of 4.3, LIST and GRID support the MASK operation, both in READs and Populating, as seen in this section. For example:&lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;row,col,LIST rows/cols,MASK&amp;quot; :  mask_array&lt;br /&gt;
&lt;br /&gt;
This restricts the rows (for both LIST and GRID) previously displayed to those corresponding to a “true” value in mask_array. A true value is represented in a numeric array as a value greater than zero. Negative values are not allowed in mask arrays. A string mask array may also be used with “T” and “F” values. The MASK stays in effect until 1) a new MASK is specified or 2) the contents of the control are changed with PRINT ( &amp;lt;nowiki&amp;gt;=, +, -,&amp;lt;/nowiki&amp;gt; see primary flags below).  Also, the mask array affects only the user presentation, not the result set. &lt;br /&gt;
&lt;br /&gt;
====Populating====&lt;br /&gt;
&lt;br /&gt;
The populate operation loads data into the control. In the following example four columns are loaded: &lt;br /&gt;
&lt;br /&gt;
 03010 PRINT FIELDS &amp;quot;10,20,LIST 10/80, =&amp;quot;: (MAT NAME$, MAT CITY$,MAT AGE, MAT WEIGHT)&lt;br /&gt;
      - or -&lt;br /&gt;
 03020 PRINT FIELDS &amp;quot;10,20,GRID 10/80, =&amp;quot;: (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
In this example, the fourth element of the HEADERS FIELD_FORM$ array (above) could specify rounding of WEIGHT to two decimal places. If an fkey value is specified, then double-clicking (or single clicking if S is specified) a cell will generate the specified fkey interrupt. &lt;br /&gt;
&lt;br /&gt;
Permissible leading attribute values are:&lt;br /&gt;
&lt;br /&gt;
===== Primary Flags  =====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;=&#039;&#039;&#039; &lt;br /&gt;
| Replace any previous data&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;+&#039;&#039;&#039; &lt;br /&gt;
| Add to any previously populated data (this allows loading in chunks)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039; &lt;br /&gt;
| Insert data ahead of previously populated data (4.16+)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Secondary Flags  ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;R&#039;&#039;&#039; &lt;br /&gt;
| Load one row at a time (the default - use grouped IO parens)&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;C&#039;&#039;&#039; &lt;br /&gt;
| Load one column at a time - This is for loading multiple columns of the same data type&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;L&#039;&#039;&#039; &lt;br /&gt;
| Provide the FKEY (see INPUT below) or Enter interrupt if the user presses up arrow or page up in the first field, or down arrow or page down in the last field. Note that this is not specified in the individual field leading attributes.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;S&#039;&#039;&#039; &lt;br /&gt;
| Single click to activate an Enter or FKEY event (otherwise a double click is required) (4.17+)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; Note that the following example will NOT work- &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT FIELDS &amp;quot;10,20,LIST 10/80,=C&amp;quot;: MAT NAME$,MAT CITY$,MAT AGE,MAT WEIGHT&lt;br /&gt;
&lt;br /&gt;
The reason is that only MAT NAME$ will reach the list. MAT CITY$, MAT AGE and MAT WEIGHT will be associated with subsequent fields. Multiple arrays provided to a single control must be grouped with parentheses. &lt;br /&gt;
&lt;br /&gt;
Populating a two-dimensional object by row with grouped IO means NAME$(1) will go into (1,1), AGE(1) will go into (1,2) and WGT(1) will go into (1,3) and so on. If a single array (MAT DATA$) is specified instead of a group, MAT DATA$ is applied horizontally instead of vertically. So DATA$(1) - DATA$(3) will be the first row and DATA$(4) - DATA$(6) will be the next row and so on. &lt;br /&gt;
&lt;br /&gt;
Populating a two dimensional grid by column with an array named DATA$ means that DATA$(1) goes in (1,1) and DATA$(2) goes in (2,1) and DATA$(3) goes in (3,1). Therefore the first however many values of DATA refer to the first column and the second however many values of DATA refer to the second column. So if there are 3 columns and UDIM(DATA$) = 90 then DATA$(1)-DATA$(30) is the first column, and DATA$(31) - DATA$(60) is the second column and DATA$(61) - DATA$(90) is the last column. &lt;br /&gt;
&lt;br /&gt;
For example, using the following information, each example demonstrates how the grid will be filled:&lt;br /&gt;
&lt;br /&gt;
MAT NAME$ = George, Peter, Tom &lt;br /&gt;
&lt;br /&gt;
MAT CITY$ = Dallas, Detroit, Denver &lt;br /&gt;
&lt;br /&gt;
MAT AGE$ = 42, 23, 35 &lt;br /&gt;
&lt;br /&gt;
MAT WEIGHT$ = 180, 212, 193 &lt;br /&gt;
&lt;br /&gt;
 00200 PRINT FIELDS &amp;quot;10,20,GRID 10/80, =&amp;quot;: (MAT NAME$, MAT CITY$,MAT AGE$, MAT WEIGHT$)&lt;br /&gt;
&lt;br /&gt;
Peter, Detroit, 23, 212 &lt;br /&gt;
&lt;br /&gt;
Tom, Denver, 35, 193 &lt;br /&gt;
&lt;br /&gt;
 00200 PRINT FIELDS &amp;quot;10,20,GRID 10/80, =C&amp;quot;: (MAT NAME$, MAT CITY$,MAT AGE$, MAT WEIGHT$)&lt;br /&gt;
&lt;br /&gt;
Dallas, Detroit, Denver &lt;br /&gt;
&lt;br /&gt;
42, 23, 35 &lt;br /&gt;
&lt;br /&gt;
180, 212, 193 &lt;br /&gt;
&lt;br /&gt;
As you can see using C with grouped arrays is counter-intuitive and doesn&#039;t fit well. C is most useful with a single array that should be loaded vertically down several columns. &lt;br /&gt;
&lt;br /&gt;
===== Grid Validation  =====&lt;br /&gt;
&lt;br /&gt;
GRIDs are now validated as each cell is exited instead of when control is passed to the BR program after all data is entered.&lt;br /&gt;
&lt;br /&gt;
===== Color and Font changes in Cells  =====&lt;br /&gt;
&lt;br /&gt;
The attributes that determine font, color and style in each cell can be set for an entire column by including these parameters in the heading FORM array. Individual cells can then be changed using a PRINT statement. &lt;br /&gt;
&lt;br /&gt;
The format of the print statement is &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT #WINNO, fields &amp;quot;2,2,LIST 10/60,ATTR&amp;quot;:(mat start, mat end, mat attribute$)&lt;br /&gt;
&lt;br /&gt;
With the following parameter descriptions: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;mat start&#039;&#039;&#039; &lt;br /&gt;
| contains the cell number(s) where the attribute chain begins,&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;mat end&#039;&#039;&#039; &lt;br /&gt;
| contains the last cell number where the attribute applies&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;mat attribute$&#039;&#039;&#039; &lt;br /&gt;
| contains the attribute specification that should be applied to the cell range(s) specified.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the 2d control is a GRID, then mat Start and mat End refer to starting and ending Cell Numbers. If the 2d control is a listview, then mat Start and mat End refer to starting and ending Row Numbers. &lt;br /&gt;
&lt;br /&gt;
The attributes specified for any COLUMN can be overridden on a cell basis by specifying the starting cell number, ending cell number, and the overriding attributes in three arrays that are printed to the grid window with the same grid specificatoins and the key word &amp;quot;ATTR&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
 02420 PRINT #BLISTWIN,FIELDS BLISTSPEC$&amp;amp;amp;&amp;quot;,ATTR&amp;quot;: (MAT BROWS,MAT BROWE,MAT BATT$)&lt;br /&gt;
&lt;br /&gt;
In the above example, BLISTWIN is the window number, BLISTSPEC$ is the grid specification (&amp;quot;GRID 10/40&amp;quot; for example), BROWS is an array holding the starting cell number, BROWE is an array holding the ending cell number, and BATT$ is an array holding the overriding attributes. In a list the attributes of the first cell in the row controls the appearance of the entire row.&lt;br /&gt;
&lt;br /&gt;
 01500 PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,ATTR&amp;quot;: (mat start, mat end, mat attr$)&lt;br /&gt;
&lt;br /&gt;
The above example overrides the attributes of a range of cells/rows for a GRID/LIST display. This allows you to shade or otherwise alter the display of a range of cells / rows in a 2D control.&lt;br /&gt;
&lt;br /&gt;
====Aggregate Sorting====&lt;br /&gt;
BR supports aggregated sorting for LISTs and GRIDs. This means when clicking &lt;br /&gt;
on various column headings or programmatically sorting columns, fields of &lt;br /&gt;
equal values retain their previous order within their new groupings (4.2).&lt;br /&gt;
&lt;br /&gt;
==== Numeric Column Sorting  ====&lt;br /&gt;
&lt;br /&gt;
2D controls now facilitate numeric column sorting. This works well in conjunction with the new [[Date (Format Specification)|DATE]] field format (see release notes [[4.16]]) where the data is stored as day of century, but is displayed as a formatted date. It also works with all numeric columns.&lt;br /&gt;
&lt;br /&gt;
If a listview columns form spec if given as DATE(mm/dd/ccyy), for example, then any time that column is sorted, either as a result of the user clicking on the column heading, or the program giving the sort command (shown below), the dates are properly sorted even though they&#039;re displayed as mm/dd/ccyy. For this to work, the data has to be given in the julian days format, see the [[DAYS]] function for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In versions 4.2 and higher the syntax for sorting a listview is: &lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column number }&lt;br /&gt;
&lt;br /&gt;
To sort in reverse order, sort the column twice:&lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column number }&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { same column number }&lt;br /&gt;
&lt;br /&gt;
This has been extended in version 4.3 to allow a numeric array instead of a scalar. If an array is given, it is assumed to be in the same format that SORT_ORDER returns. The new format is: &lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column-number | numeric-array }&lt;br /&gt;
&lt;br /&gt;
Where the numeric-array has one element for each column left to right. BR will resort the columns in the requested order. &lt;br /&gt;
&lt;br /&gt;
The numeric array values indicating the order of column sorting to be performed do not need to exactly match the standard format. e.g Fractions are allowed, the values can fall within any range, and there does not need to be trailing zero elements for unsorted columns.&lt;br /&gt;
&lt;br /&gt;
==== NOSORT for Columns  ====&lt;br /&gt;
As of 4.2, the &#039;&#039;&#039;NoSort&#039;&#039;&#039; parameter is used to prevent users from sorting columns of a Grid or List. &lt;br /&gt;
&lt;br /&gt;
For the statement: &lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;10,20,GRID 10/80,HEADERS,[hdrs],1520&amp;quot;: (MAT HEADINGS$, MAT WIDTHS, MAT FIELD_FORMS$) &lt;br /&gt;
&lt;br /&gt;
The field attribute &amp;quot;^nosort&amp;quot; appearing in the MAT FIELD_FORM$ prevents the sorting of a grid or listview in response to the user clicking on the corresponding column header. This does not prevent programs from sorting on those columns.&lt;br /&gt;
&lt;br /&gt;
==== Range Input  ====&lt;br /&gt;
&lt;br /&gt;
The following examples are used in versions 4.3 and higher. In these examples BR will redimension the receiving arrays as needed: &lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, CELL, RANGE&amp;quot; :&lt;br /&gt;
             start, end, MAT Data$&lt;br /&gt;
&lt;br /&gt;
This reads the specified range of cells. BR redimensions MAT Data$ as needed. Note that CELL may now be used with LIST. Previously, LISTs were only addressable by row. &lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, ROW, RANGE&amp;quot; :&lt;br /&gt;
             (start:=7), (end:=11), ( MAT Array1$, MAT Array2, MAT Array3$ )&lt;br /&gt;
&lt;br /&gt;
This reads the cells in rows 7 through 11. The receiving arrays are re-dimensioned as appropriate. &lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,GRID rows/cols, ROW, RANGE&amp;quot;:&lt;br /&gt;
             MAT start, MAT end, ( MAT Data1$, MAT Data2$, MAT Data3 )&lt;br /&gt;
&lt;br /&gt;
This reads one or more ranges of rows. &lt;br /&gt;
&lt;br /&gt;
A more detailed example of this is: &lt;br /&gt;
&lt;br /&gt;
 100 ! create and populate a LIST control &lt;br /&gt;
 200 MAT START(3) : MAT END(3)&lt;br /&gt;
 210 READ MAT START, MAT END&lt;br /&gt;
 220 DATA 7,21,33&lt;br /&gt;
 230 DATA 11,21,38&lt;br /&gt;
 240 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, ROW, RANGE&amp;quot;&amp;amp;nbsp;: MAT START,&lt;br /&gt;
            MAT END, ( MAT Array1$, MAT Array2, MAT Array3$ )&lt;br /&gt;
&lt;br /&gt;
This reads 12 rows of data ( row 7-11, row 21 and rows 33-38 ). &lt;br /&gt;
&lt;br /&gt;
==== Range Output  ====&lt;br /&gt;
&lt;br /&gt;
The following examples are valid for versions [[4.3]] and higher. By default, RANGE output refers to rows. The special keyword CELL_RANGE is used to denote the specification of cell ranges. Additionally, the use of scalars versus arrays for start and end values determines important characteristics of the output process. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; Using Scalars For Range Specification &lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;7,8,GRID 10/75, RANGE&amp;quot;: start, end, MAT Data$&lt;br /&gt;
&lt;br /&gt;
This replaces the values in rows numbered &#039;start&#039; through &#039;end&#039; with the data in MAT Data$. The size of MAT Data$ must be a multiple of the number of columns in the GRID or an error is generated. &lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;7,8,LIST 10/75, RANGE&amp;quot;: start, end, (MAT NAME$,                                   MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
This replaces the values in ROWs numbered &#039;start&#039; through &#039;end&#039; with the data from MATs NAME$, CITY$, AGE and WEIGHT. The data arrays must all be dimensioned the same. &lt;br /&gt;
&lt;br /&gt;
==== Insertion and Deletion with RANGE ====&lt;br /&gt;
&lt;br /&gt;
The number of rows being output do not need to match the number of rows being replaced. To delete a range of rows, output one or more grouped arrays with zero elements. &lt;br /&gt;
&lt;br /&gt;
The following examples are valid for versions 4.3 and higher. Using the following statement, various scenarios are described. &lt;br /&gt;
&lt;br /&gt;
  PRINT FIELDS &amp;quot;7,8,LIST 10/75, RANGE&amp;quot;: start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
 start=7, end=11, and the arrays have been DIMed to nine elements&lt;br /&gt;
 Result- Nine rows replace five, and the total content of the control is expanded by 4 rows.&lt;br /&gt;
&lt;br /&gt;
 start=7, end=11, and the arrays are DIMed to zero elements&lt;br /&gt;
 Result- Five rows are deleted, and the total size of the control is reduced by 5 rows.&lt;br /&gt;
&lt;br /&gt;
 start=7, end=0 (anything less than 7), and the arrays are DIMed to support three rows&lt;br /&gt;
 Result- Three rows are inserted ahead of row seven and the total content of the control is expanded by three rows&lt;br /&gt;
&lt;br /&gt;
 start=5000, end={any value}, the control only has 482 rows, and the source arrays are DIMed to support eleven rows&lt;br /&gt;
 Result- Eleven rows are appended to the end of the control and become rows 483 through 493.&lt;br /&gt;
&lt;br /&gt;
==== Outputting Ranges of Cells  ====&lt;br /&gt;
&lt;br /&gt;
The following examples are valid for versions 4.3 and higher. &lt;br /&gt;
&lt;br /&gt;
Ranges of cells may be output in conjunction with the CELL_RANGE keyword. &lt;br /&gt;
&lt;br /&gt;
  PRINT FIELDS &amp;quot;7,8,LIST 10/75, CELL_RANGE&amp;quot;: start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
                                - or -&lt;br /&gt;
&lt;br /&gt;
  PRINT FIELDS &amp;quot;7,8,GRID 10/75, CELL_RANGE&amp;quot;: start, end, MAT Data$&lt;br /&gt;
&lt;br /&gt;
In this case, start and end specify cells instead of rows. If insertion or deletion is indicated by dimensioning the data arrays to greater or fewer elements than are being replaced, then the data must be a multiple of the number of columns. Insertion and deletion is only valid in terms of rows, even when cell subscripts are used to specify ranges. In such cases, if the cell subscripts are not on row boundaries, an error is generated. &lt;br /&gt;
&lt;br /&gt;
  PRINT FIELDS &amp;quot;7,8,GRID 10/75, CELL_RANGE&amp;quot;: start, start, Data$&lt;br /&gt;
&lt;br /&gt;
In this example, the value in one cell is replaced with the content of a scalar.&lt;br /&gt;
&lt;br /&gt;
==== Using Arrays For Range Specification  ====&lt;br /&gt;
&lt;br /&gt;
If the start and end specifications are array denoting multiple ranges, there must be a one to one correspondence between the number of rows specified and those in the data. This method implies replacement only and insertion or deletion is not allowed. &lt;br /&gt;
&lt;br /&gt;
The data flow that this feature was designed to support is one where the user is presented with a LIST or GRID where multiple rows have been either selected or changed before returning control to the program and the program is responding by updating something on those rows. &lt;br /&gt;
&lt;br /&gt;
The program begins by presenting a 2D control to the user and reading the the control with type ROWSUB or SUB. Type SUB only works for GRIDs where all colmns have the same data type. Of course the subscripts are read into a numeric array which BR redimensions as appropriate. Then the program reads the changed or selected data with NOWAIT. (This resets the CHG flags in the control.) The program then changes either row (ROWSUB) or cell (SUB) data and outputs the results using the subscript array as both the start and end specification. Other scenarios are possible but this is the primary intended use. &lt;br /&gt;
&lt;br /&gt;
The following examples are valid for versions 4.3 and higher: &lt;br /&gt;
&lt;br /&gt;
  100 ! create and populate a GRID --&lt;br /&gt;
  200 INPUT FIELDS &amp;quot;row,col,GRID rows/cols,ROWSUB,CHG&amp;quot;: MAT Rowsubs&lt;br /&gt;
         (Reading subscripts does not reset the CHG flags in the control.)&lt;br /&gt;
  210 INPUT FIELDS &amp;quot;row,col,GRID rows/cols,ROW,CHG,NOWAIT&amp;quot;: ( MAT Data1$,&lt;br /&gt;
        MAT Data2, MAT Data3$ )&lt;br /&gt;
          BR redimensions the receiving arrays as needed.&lt;br /&gt;
         (Reading the data also resets the CHG flags in the control.)&lt;br /&gt;
&lt;br /&gt;
  220 ! process the changed rows now present in the data arrays --&lt;br /&gt;
  300 PRINT FIELDS &amp;quot;row,col,GRID rows/cols,RANGE&amp;quot;: MAT Rowsubs,&lt;br /&gt;
                   MAT Rowsubs, ( MAT Data1$, MAT Data2, MAT Data3$ )&lt;br /&gt;
&lt;br /&gt;
This outputs the updated rows. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Grid and List BR_VB Similarities  ====&lt;br /&gt;
Before introducing grids and lists in BR, similar effects could be achieved using BR_VB to work with Visual Basic. If you were familiar with BR_VB, the following notes may be of interest:&lt;br /&gt;
&lt;br /&gt;
Grid and list controls work like the BR_VB interface except headers now specify the form of each column and a new input type has been added: &lt;br /&gt;
&lt;br /&gt;
A multi column LISTview- &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT FIELDS &amp;quot;10,20,LIST 10/80,HEADERS[,hdrs][,fkey]&amp;quot;: (MAT HEADINGS$, MAT WIDTHS, MAT FORMS$) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note-&#039;&#039;&#039; Widths are expressed in character positions, not percentages like they are in BR_VB. &lt;br /&gt;
&lt;br /&gt;
The populate operation- &lt;br /&gt;
&lt;br /&gt;
 00200 PRINT FIELDS &amp;quot;10,20,LIST 10/80,=&amp;quot;: (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
Read-Ctl type: CNT (in place of CELLROWSUB) returns a single numeric value which is the number of subscripts available to read. In the case of grids, this is the number of cells. In the case of LISTviews, this is the number of rows. &lt;br /&gt;
&lt;br /&gt;
 00110 INPUT FIELDS &amp;quot;10,20,LIST 10/80,ROWCNT,SEL&amp;quot;: avail_rows&amp;amp;nbsp;! # of selected rows&lt;br /&gt;
 00120 MAT DATA$(3 * avail_rows)         &amp;amp;nbsp;! redimension.. 3 cols x selected rows&lt;br /&gt;
 00130 INPUT FIELDS &amp;quot;10,20,LIST 10/80,ROW,SEL,NOWAIT&amp;quot;: MAT DATA$&amp;amp;nbsp;! read rows&lt;br /&gt;
&lt;br /&gt;
====See Also: ====&lt;br /&gt;
[[Grids Tutorial]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Widget]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10678</id>
		<title>Filter</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10678"/>
		<updated>2015-10-29T21:24:53Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Grid and list &#039;&#039;&#039;filter&#039;&#039;&#039; search fields are available as of BR! [[4.3]] for [[grids and lists]].&lt;br /&gt;
&lt;br /&gt;
A new field type is defined (similar to [[SEARCH]]):&lt;br /&gt;
&lt;br /&gt;
[[image:Filter.png|900px]]&lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;nn,nn,15/FILTER 10,leading-attributes,row,col,grid column to search [, filter-type] [, CASE]&amp;quot;: string-value&lt;br /&gt;
&lt;br /&gt;
For example: &lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;4,50,15/FILTER 10,,10,10,2,ALL&amp;quot;: Findfield$&lt;br /&gt;
&lt;br /&gt;
This example combines a filter box (which will search everything in the list) and the rinput fields for a list selection:&lt;br /&gt;
&lt;br /&gt;
 rinput fields &amp;quot;4,8,78/FILTER 30,/w:w,5,6,Fullrow,all;5,6,list 21/80,rowsub,selone&amp;quot;: foundvar$,selection&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nn and nn&#039;&#039;&#039; are the row and column to position the field on the screen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Size/&#039;&#039;&#039; and &#039;&#039;&#039;Characters&#039;&#039;&#039; signifies how large the filter field will be in columns, and how many characters can be entered into it. In the example, &#039;&#039;&#039;15/ and 10&#039;&#039;&#039; provide a 15 column field where the operator can enter 10 characters. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Leading attributes&#039;&#039;&#039; can be any attributes desired (optional). &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Row and col&#039;&#039;&#039; are the starting row and column of the grid or list you wish to search.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grid column to search&#039;&#039;&#039; is the number of the grid column the filter will test against. FULLROW can be used here to searchall the columns in each row. &lt;br /&gt;
&lt;br /&gt;
====Filter Types====&lt;br /&gt;
*LEADING - Filter searching is done left justified using only leading characters (default).&lt;br /&gt;
*WORD - Each word is leading matched.&lt;br /&gt;
*ALL - The entire string is searched for a match (similar to [[POS]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CASE&#039;&#039;&#039; may optionally be used to make all searching case sensitive. Case insensitivity is the default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;String-value&#039;&#039;&#039; is the variable name which will apply to whatever the operator enters into the field for searching. &lt;br /&gt;
&lt;br /&gt;
For both FILTER and [[Srch]], the up and down arrows now affect only the selection bar in the grid/list being presented.&lt;br /&gt;
&lt;br /&gt;
====Note====&lt;br /&gt;
&lt;br /&gt;
* FILTER is subordinate to MASK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====See Also====&lt;br /&gt;
&lt;br /&gt;
* [[Filter_Delimiters]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Widget]]&lt;br /&gt;
[[Category:Grid and List]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10677</id>
		<title>Filter</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10677"/>
		<updated>2015-10-29T20:26:21Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Parameters */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Grid and list &#039;&#039;&#039;filter&#039;&#039;&#039; search fields are available as of BR! [[4.3]] for [[grids and lists]].&lt;br /&gt;
&lt;br /&gt;
A new field type is defined (similar to [[SEARCH]]):&lt;br /&gt;
&lt;br /&gt;
[[image:Filter.png|900px]]&lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;nn,nn,15/FILTER 10,leading-attributes,row,col,grid column to search [, filter-type] [, CASE]&amp;quot;: string-value&lt;br /&gt;
&lt;br /&gt;
For example: &lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;4,50,15/FILTER 10,,10,10,2,ALL&amp;quot;: Findfield$&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nn and nn&#039;&#039;&#039; are the row and column to position the field on the screen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Size/&#039;&#039;&#039; and &#039;&#039;&#039;Characters&#039;&#039;&#039; signifies how large the filter field will be in columns, and how many characters can be entered into it. In the example, &#039;&#039;&#039;15/ and 10&#039;&#039;&#039; provide a 15 column field where the operator can enter 10 characters. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Leading attributes&#039;&#039;&#039; can be any attributes desired (optional). &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Row and col&#039;&#039;&#039; are the starting row and column of the grid or list you wish to search.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grid column to search&#039;&#039;&#039; is the number of the grid column the filter will test against. FULLROW can be used here to searchall the columns in each row. &lt;br /&gt;
&lt;br /&gt;
====Filter Types====&lt;br /&gt;
*LEADING - Filter searching is done left justified using only leading characters (default).&lt;br /&gt;
*WORD - Each word is leading matched.&lt;br /&gt;
*ALL - The entire string is searched for a match (similar to [[POS]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CASE&#039;&#039;&#039; may optionally be used to make all searching case sensitive. Case insensitivity is the default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;String-value&#039;&#039;&#039; is the variable name which will apply to whatever the operator enters into the field for searching. &lt;br /&gt;
&lt;br /&gt;
For both FILTER and [[Srch]], the up and down arrows now affect only the selection bar in the grid/list being presented.&lt;br /&gt;
&lt;br /&gt;
====Note====&lt;br /&gt;
&lt;br /&gt;
* FILTER is subordinate to MASK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====See Also====&lt;br /&gt;
&lt;br /&gt;
* [[Filter_Delimiters]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Widget]]&lt;br /&gt;
[[Category:Grid and List]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10676</id>
		<title>Filter</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10676"/>
		<updated>2015-10-29T20:20:47Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Parameters */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Grid and list &#039;&#039;&#039;filter&#039;&#039;&#039; search fields are available as of BR! [[4.3]] for [[grids and lists]].&lt;br /&gt;
&lt;br /&gt;
A new field type is defined (similar to [[SEARCH]]):&lt;br /&gt;
&lt;br /&gt;
[[image:Filter.png|900px]]&lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;nn,nn,15/FILTER 10,leading-attributes,row,col,grid column to search [, filter-type] [, CASE]&amp;quot;: string-value&lt;br /&gt;
&lt;br /&gt;
For example: &lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;4,50,15/FILTER 10,,10,10,2,ALL&amp;quot;: Findfield$&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nn and nn&#039;&#039;&#039; are the row and column to position the field on the screen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Size/&#039;&#039;&#039; and &#039;&#039;&#039;Characters&#039;&#039;&#039; signifies how large the filter field will be in columns, and how many characters can be entered into it. In the example, &#039;&#039;&#039;15/ and 10&#039;&#039;&#039; provide a 15 column field where the operator can enter 10 characters. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Leading attributes&#039;&#039;&#039; can be any attributes desired (optional). &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Row and col&#039;&#039;&#039; are the starting row and column of the grid or list you wish to search.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grid column to search&#039;&#039;&#039; is the number of the grid column the filter will test against. If FULLROW is used here then all the columns in each row will be searched. &lt;br /&gt;
&lt;br /&gt;
====Filter Types====&lt;br /&gt;
*LEADING - Filter searching is done left justified using only leading characters (default).&lt;br /&gt;
*WORD - Each word is leading matched.&lt;br /&gt;
*ALL - The entire string is searched for a match (similar to [[POS]]).&lt;br /&gt;
*FULLROW - Will search each cell in a row. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CASE&#039;&#039;&#039; may optionally be used to make all searching case sensitive. Case insensitivity is the default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;String-value&#039;&#039;&#039; is the variable name which will apply to whatever the operator enters into the field for searching. &lt;br /&gt;
&lt;br /&gt;
For both FILTER and [[Srch]], the up and down arrows now affect only the selection bar in the grid/list being presented.&lt;br /&gt;
&lt;br /&gt;
====Note====&lt;br /&gt;
&lt;br /&gt;
* FILTER is subordinate to MASK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====See Also====&lt;br /&gt;
&lt;br /&gt;
* [[Filter_Delimiters]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Widget]]&lt;br /&gt;
[[Category:Grid and List]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10675</id>
		<title>Filter</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Filter&amp;diff=10675"/>
		<updated>2015-10-29T20:14:48Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Parameters */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Grid and list &#039;&#039;&#039;filter&#039;&#039;&#039; search fields are available as of BR! [[4.3]] for [[grids and lists]].&lt;br /&gt;
&lt;br /&gt;
A new field type is defined (similar to [[SEARCH]]):&lt;br /&gt;
&lt;br /&gt;
[[image:Filter.png|900px]]&lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;nn,nn,15/FILTER 10,leading-attributes,row,col,grid column to search [, filter-type] [, CASE]&amp;quot;: string-value&lt;br /&gt;
&lt;br /&gt;
For example: &lt;br /&gt;
&lt;br /&gt;
 RINPUT FIELDS &amp;quot;4,50,15/FILTER 10,,10,10,2,ALL&amp;quot;: Findfield$&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nn and nn&#039;&#039;&#039; are the row and column to position the field on the screen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Size/&#039;&#039;&#039; and &#039;&#039;&#039;Characters&#039;&#039;&#039; signifies how large the filter field will be in columns, and how many characters can be entered into it. In the example, &#039;&#039;&#039;15/ and 10&#039;&#039;&#039; provide a 15 column field where the operator can enter 10 characters. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Leading attributes&#039;&#039;&#039; can be any attributes desired (optional). &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Row and col&#039;&#039;&#039; are the starting row and column of the grid or list you wish to search.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grid column to search&#039;&#039;&#039; is the number of the grid column the filter will test against. If FULLROW is used then all cells will be searched. See [[#Tip|tip]] below.&lt;br /&gt;
&lt;br /&gt;
====Filter Types====&lt;br /&gt;
*LEADING - Filter searching is done left justified using only leading characters (default).&lt;br /&gt;
*WORD - Each word is leading matched.&lt;br /&gt;
*ALL - The entire string is searched for a match (similar to [[POS]]).&lt;br /&gt;
*FULLROW - Will search each cell in a row. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CASE&#039;&#039;&#039; may optionally be used to make all searching case sensitive. Case insensitivity is the default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;String-value&#039;&#039;&#039; is the variable name which will apply to whatever the operator enters into the field for searching. &lt;br /&gt;
&lt;br /&gt;
For both FILTER and [[Srch]], the up and down arrows now affect only the selection bar in the grid/list being presented.&lt;br /&gt;
&lt;br /&gt;
====Note====&lt;br /&gt;
&lt;br /&gt;
* FILTER is subordinate to MASK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====See Also====&lt;br /&gt;
&lt;br /&gt;
* [[Filter_Delimiters]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Widget]]&lt;br /&gt;
[[Category:Grid and List]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Time&amp;diff=10673</id>
		<title>Time</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Time&amp;diff=10673"/>
		<updated>2015-10-27T23:16:40Z</updated>

		<summary type="html">&lt;p&gt;Laura: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;Time&#039;&#039;&#039; [[command]] sets the system clock and determines the time that the [[TIME$]] function returns.&lt;br /&gt;
&lt;br /&gt;
==Comments and Examples==&lt;br /&gt;
&lt;br /&gt;
The TIME command uses the 24-hour clock system. 12:01 a.m. becomes 00:01 in this system; 11:59 p.m. is 23:59.&lt;br /&gt;
&lt;br /&gt;
The following example sets the hour to 16 (equivalent to 4:00 p.m. on a twelve-hour clock), the minutes to 35, and the seconds to 42:&lt;br /&gt;
&lt;br /&gt;
 TIME 16:35:42&lt;br /&gt;
&lt;br /&gt;
The next command resets the time to 00:00:00:&lt;br /&gt;
&lt;br /&gt;
 TIME :&lt;br /&gt;
&lt;br /&gt;
The following command resets the time to 00:00:37:&lt;br /&gt;
&lt;br /&gt;
 TIME ::37&lt;br /&gt;
&lt;br /&gt;
The time is reset to 3:00:14 with the following command:&lt;br /&gt;
&lt;br /&gt;
 TIME 3::14&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
 TIME [hh][{:|-}][mm][{:|-}][ss]&lt;br /&gt;
[[Image:Time.png]]&lt;br /&gt;
&lt;br /&gt;
==Defaults==&lt;br /&gt;
&lt;br /&gt;
#Display the current time in hh:mm:ss format.&lt;br /&gt;
#Set to zero.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
&lt;br /&gt;
Time parameters may be separated either with a dash (-) or a colon (:).&lt;br /&gt;
&#039;&#039;&#039;hh&#039;&#039;&#039; parameter is a one or two-digit number from 0 to 24 which represents the hour of the day.&lt;br /&gt;
&#039;&#039;&#039;mm&#039;&#039;&#039; parameter is a one or two-digit number from 0 to 60 which represents the number of minutes past the hour.&lt;br /&gt;
&#039;&#039;&#039;ss&#039;&#039;&#039; parameter is a one or two-digit number from 0 to 60 which represents the number of seconds past the minute.&lt;br /&gt;
&lt;br /&gt;
==Technical Considerations==&lt;br /&gt;
&lt;br /&gt;
Changes to the time apply only to the issuing workstation - current session only.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Commands]]&lt;br /&gt;
[[Category:Information Commands]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=File:Opendisplay.png&amp;diff=10672</id>
		<title>File:Opendisplay.png</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=File:Opendisplay.png&amp;diff=10672"/>
		<updated>2015-10-26T20:07:43Z</updated>

		<summary type="html">&lt;p&gt;Laura: uploaded a new version of &amp;amp;quot;File:Opendisplay.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=Grid_and_List&amp;diff=10665</id>
		<title>Grid and List</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=Grid_and_List&amp;diff=10665"/>
		<updated>2015-10-13T16:15:00Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* Parameters */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Grid&#039;&#039;&#039; and &#039;&#039;&#039;List&#039;&#039;&#039; (a.k.a. &#039;&#039;&#039;ListView&#039;&#039;&#039;) are [[Two dimensional controls]], which means that they contain rows and columns. GRIDs are normally used for data entry, while LISTs are used only for selection. In Business Rules, outputting to these controls is done with [[Print Fields]] and inputting from them is done with [[Input Fields]]. Each field specification pertains to one [[Control]]. However, a single FIELD specification can pertain to a parenthesized group of arrays. When using Grids and Lists, first the header must be populated, and then the data within the rows. &lt;br /&gt;
&lt;br /&gt;
The [[INPUT FIELDS]] specification states Grid or List as the field type. The display area is specified in terms of rows and columns separated by a slash. The following parameter, instead of being leading field attributes, is a secondary keyword indicating the type (CNT/SUB/CELL/ROWCNT/ROWSUB/ROW) of output or input operation to be performed. The next parameter further qualifies the IO operation (CHG/SEL/ALL/CUR/NEXT). Normally this trailing attribute is an [[FKEY]] value which is shifted right one parameter in this context. &lt;br /&gt;
&lt;br /&gt;
It is useful to work with [[2D Controls]] in terms of rows versus cells, particularly when the columns are dissimilar. A complete set of row oriented parameters are provided for that purpose. Output operations support the mass populating of 2D controls row by row. And input operations can be row oriented as well. The keywords associated with row processing are R, ROWCNT, ROWSUB, and ROW. &lt;br /&gt;
&lt;br /&gt;
RINPUT does not work with 2D controls because the output statements are somewhat different from the input statements. The output consists of setting up the columns, including providing the column headings, and populating the control with data. The input consists of identifying what has changed in a manner that enables selective data retrieval and corresponding file updating. &lt;br /&gt;
&lt;br /&gt;
If the user clicks on a column heading the GRID or LIST will be sorted on that column. Sorting is done in terms of rows. Such sorting of these controls has no affect on the BR program. The information returned to BR will be as though no sorting were performed. If a control&#039;s population is increased by populating with the plus (+) flag, the control will be resequenced back to its original order before the data is added. One way a program can restore the original displayed order of a GRID or LIST is to populate it incrementally (+) with no data. As of version 4.1 and higher, if a GRID input is attempted on a protected field, BR issues a Bell. &lt;br /&gt;
&lt;br /&gt;
Shift+PgUp and Shift+PgDn selects within a List/Grid. &lt;br /&gt;
&lt;br /&gt;
Grids and lists are compatible with the [[FILTER]] field, which works like a search bar. &lt;br /&gt;
&lt;br /&gt;
In GRIDs and LISTs only, string arrays may be used to process numeric values. BR automatically performs [[VAL]] and [[STR]] conversions as needed.  If string data is passed to a numeric field type such as N or DATE then it is automatically converted to numeric form for internal processing (4.2).&lt;br /&gt;
&lt;br /&gt;
As of Business Rules! versions [[4.3]]+, arrays are automatically resized when receiving data from 2D INPUT operations. This also applies to grouped arrays. Automatic resizing only applies to one dimensional arrays and does not occur when INPUTing into two dimensional arrays. For example, where all arrays are one dimensional and may have the incorrect number of elements:&lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, ROW, ALL&amp;quot;&amp;amp;nbsp;: ( MAT Array1$,&amp;lt;span style=&amp;quot;font-family: monospace;&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;MAT Array2$, MAT Array3, MAT Array4, MAT Array5$ )  &lt;br /&gt;
&lt;br /&gt;
====FKey Processing====&lt;br /&gt;
&lt;br /&gt;
An [[FKey]] value can be associated with a LIST or GRID control by specifying the FKey number during either output or input operations. Once an Fkey value is specified, the control retains the setting until it is reset. An FKey value can be cleared by specifying an Fkey value of minus one (-1). &lt;br /&gt;
&lt;br /&gt;
When a LIST or GRID has an FKey value set processing is dependent on whether or not the 2D control is being processed by an INPUT FIELDS statement: &lt;br /&gt;
&lt;br /&gt;
*Displayed but inactive- Single clicking any cell produces the FKey interrupt. &lt;br /&gt;
*Active (participating in Input Fields)- Double clicking any cell produces an FKey completion.&lt;br /&gt;
&lt;br /&gt;
Formerly, [[CURROW]] and [[CURCOL]] represented the character position where the cursor was when FIELDS processing is completed. This is still true except when the most recent field processed is a [[2D control]]. &lt;br /&gt;
&lt;br /&gt;
When FIELDS processing ends and control is returned to the program while the &#039;current&#039; control is of type LIST or GRID, CURROW and CURCOL are set to the current cell row and column within the 2D control instead of the character position relative to the window.&lt;br /&gt;
&lt;br /&gt;
====GRID CURSOR MOVEMENT====&lt;br /&gt;
When field + or - is keyed BR Always returns fkey values of 114 or 115 in&lt;br /&gt;
both navigation and edit mode and for any type of data. (This assumes the X&lt;br /&gt;
attribute or some other attribute returns control to the program.)&lt;br /&gt;
&lt;br /&gt;
In edit mode, Field +/- always forces the signing of a numeric field, &lt;br /&gt;
whether or not the field type is PIC.&lt;br /&gt;
&lt;br /&gt;
In edit mode, field plus or minus right truncates any character or numeric &lt;br /&gt;
data before exiting the field.&lt;br /&gt;
&lt;br /&gt;
A new Config statement is defined to help with grid cursor movement: &lt;br /&gt;
&lt;br /&gt;
 GRID_CURSOR_MOVE  DOWN | RIGHT | NONE | DEFAULT&lt;br /&gt;
&lt;br /&gt;
This determines the field cursor position after keying Enter or &lt;br /&gt;
Field +/-. Both navigation and edit mode produce the same resulting cursor &lt;br /&gt;
position.&lt;br /&gt;
&lt;br /&gt;
Default Enter and Field +/- cursor movement are unchanged. Field plus &lt;br /&gt;
or minus perform a down arrow operation, and Enter defaults to NONE. &lt;br /&gt;
GRID_CURSOR_MOVE overrides both of these.&lt;br /&gt;
&lt;br /&gt;
====Restoring a User Sorted 2D Control====&lt;br /&gt;
&lt;br /&gt;
In versions 4.3 and higher the syntax for sorting a listview is: &lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column number }&lt;br /&gt;
&lt;br /&gt;
This has been extended to allow a numeric array instead of a scalar. If an array is given, it is assumed to be in the same format that SORT_ORDER returns. The new format is: &lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column-number | numeric-array }&lt;br /&gt;
&lt;br /&gt;
Where the numeric-array has one element for each column left to right. BR will resort the columns in the requested order. &lt;br /&gt;
&lt;br /&gt;
The numeric array values indicating the order of column sorting to be performed do not need to exactly match the standard format. e.g Fractions are allowed, the values can fall within any range, and there does not need to be trailing zero elements for unsorted columns. &lt;br /&gt;
&lt;br /&gt;
==== A multi column LISTview  ====&lt;br /&gt;
&lt;br /&gt;
 01000 PRINT FIELDS &amp;quot;10,20,LIST 10/80,HEADERS,[HDRS][,fkey]&amp;quot;: (MAT HEADINGS$,MAT WIDTHS, MAT FORMS$)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Widths are expressed in character positions.&lt;br /&gt;
&lt;br /&gt;
The [HDRS] notation refers to an optional CONFIG ATTRIBUTE HDRS specification for setting the appearance of the header row. In this case the  brackets [] are required and the term HDRS may be any bracketed attribute name. &lt;br /&gt;
&lt;br /&gt;
If a function key value (e.g. 1520) is given then when the control is not active, it may be clicked to trigger the specified interrupt similar to any other hot control. A function key interrupt is also triggered by double clicking during an Input operation. &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;MAT HEADINGS$&#039;&#039;&#039; &lt;br /&gt;
| Specifies the titles that will appear at the top of each column in the List or Grid. The format of this row may be specified by an optional parameter following HEADERS in the above example.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;MAT WIDTHS&#039;&#039;&#039; &lt;br /&gt;
| Specifies the number of characters in each column. For example if four columns are specified and the widths are given as 10, 15, 10 and 5, then the 2D control occupies 40 character positions (plus a little for the column separators) irrespective of the number of columns specified for the display area. If needed, scroll bars are used to display wider controls within the displayed area.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;MAT FORMS$&#039;&#039;&#039; &lt;br /&gt;
| Specifies the display characteristics of each column such as &amp;quot;C 12&amp;quot; or &amp;quot;PIC(z,zzz,zz#.##-)&amp;quot;. A &amp;quot;P&amp;quot; following the display parameter will cause the field to be protected and no data entry will be allowed in GRID mode.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; The field form array elements may also include a trailing comma followed by field attributes (e.g. color) that pertain to the column. &lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;10,20,LIST 10/80, = [,fkey]&amp;quot;: (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
In this example, the fourth element of the HEADERS FIELD_FORM$ array (above) could specify rounding of WEIGHT to two decimal places. If an fkey value is specified, then double-clicking (or single clicking if S is specified) a cell will generate the specified fkey interrupt.&lt;br /&gt;
&lt;br /&gt;
==== Reading a Listview or Grid  ====&lt;br /&gt;
When using INPUT FIELDS to read from a 2D control, the leading attributes specification states the type of read operation and the trailing attributes specification is the type of cell or row selection to be performed. The third parameter can optionally specify NOWAIT or an FKEY value. If it is an FKEY value, it signifies that an FKEY event should be triggered when, in navigation mode, a selection is made by double clicking or pressing the Enter key.&lt;br /&gt;
 &lt;br /&gt;
===== Syntax  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Grid.png|950px]]&lt;br /&gt;
&lt;br /&gt;
=====Parameters=====&lt;br /&gt;
Quotation marks must surround the specifications, and individual parts must be separated by commas.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Row&#039;&#039;&#039; and &#039;&#039;&#039;Column&#039;&#039;&#039; specify the space where the grid or list begins.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;List&#039;&#039;&#039; or &#039;&#039;&#039;Grid&#039;&#039;&#039;, followed by rows and columns separated by a slash determine how big the list or grid is going to be. The main difference between a list and grid is that lists are for selection only while information can be added to grids directly. &lt;br /&gt;
&lt;br /&gt;
The following &#039;&#039;&#039;Read Types&#039;&#039;&#039; are valid for both grids and lists:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;RowCnt&#039;&#039;&#039; &lt;br /&gt;
| The number of rows specified.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;RowSub&#039;&#039;&#039; &lt;br /&gt;
| The subscripts of the specified rows.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Row&#039;&#039;&#039; &lt;br /&gt;
| Read all cells in each specified row.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Colcnt&#039;&#039;&#039; &lt;br /&gt;
|The number of columns established by the header arrays. e.g. INPUT FIELDS &amp;quot;row,col,LIST rows/cols, COLCNT, ALL&amp;quot; : numeric-variable&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Sort_Order&#039;&#039;&#039; &lt;br /&gt;
|(4.3+) Provides a value of zero for each unsorted column and gives the ascending sequence of column sorts that have occurred. If a column has been reversed (double sorted) it&#039;s value will be negative. The selection typed used must be ALL. For example: INPUT FIELDS &amp;quot;row,col,GRID rows/cols, SORT_ORDER, ALL&amp;quot; : Mat NumArray, with the following history of sorting a four column GRID:&lt;br /&gt;
 column 1 (descending most recent)&lt;br /&gt;
 column 2 (ascending first sorted)&lt;br /&gt;
 column 3 (not sorted)&lt;br /&gt;
 column 4 (sorted ascending)&lt;br /&gt;
&lt;br /&gt;
SORT_ORDER would return-&lt;br /&gt;
 array(1) -&amp;gt;  -1&lt;br /&gt;
 array(2) -&amp;gt;   3&lt;br /&gt;
 array(3) -&amp;gt;   0&lt;br /&gt;
 array(4) -&amp;gt;   2&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;HEADERS&#039;&#039;&#039;&lt;br /&gt;
|(As of 4.30) The read operation returns the original PRINT FIELDS HEADER values. For example:  INPUT FIELDS &amp;quot;row,col,LIST rows/cols, HEADERS,,NOWAIT&amp;quot; : (MAT HEADINGS$,MAT WIDTHS, MAT FORMS$) The selection typed used must be ALL.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;MASK&#039;&#039;&#039;&lt;br /&gt;
|(As of 4.30) MASK can be used with Grids and Lists. As a READ type, this reads the display mask setting. For example: INPUT FIELDS &amp;quot;row,col,LIST rows/cols,MASK [,NOWAIT]&amp;quot; : mask_array. The mask array affects only the user presentation and not the data. Use RANGE processing or the CHG selection type to selectively read from a 2D control.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These Read Types are valid for Grids only:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Cnt&#039;&#039;&#039; &lt;br /&gt;
| Specify the number of cells specified (see selection types below).&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Sub&#039;&#039;&#039; &lt;br /&gt;
| Read the Cell Subscript Values (see example below).&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Cell&#039;&#039;&#039; &lt;br /&gt;
| Read each cell specified.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For the &amp;quot;Sel-type&amp;quot; parameter, the following selection types are valid for both grids and lists:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Sel&#039;&#039;&#039; &lt;br /&gt;
| Read one or more selected items.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;SelOne&#039;&#039;&#039; &lt;br /&gt;
| Select only one item.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;All&#039;&#039;&#039; &lt;br /&gt;
| Read all items in the control (except headings).&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Cur&#039;&#039;&#039; &lt;br /&gt;
| Current cell or row number.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Next (4.2+)&#039;&#039;&#039; &lt;br /&gt;
| The cell the cursor is going to next if the user moved it using an arrow or a mouse click.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Range&#039;&#039;&#039;&lt;br /&gt;
|Specifies which portion of a 2D control is to be input. (As of 4.3) [[#Range Input|See Below]].&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Cell_Range&#039;&#039;&#039;&lt;br /&gt;
|A special type of output range. (As of 4.3) [[#Range Input|See Below]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This Selection Type is valid for Grids only:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;Chg&#039;&#039;&#039; &lt;br /&gt;
| All items changed since the last &#039;=&#039; populate or the last CHG retrieval of cell/row contents.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Read Qualifier&#039;&#039;&#039; is an optional parameter to help the read. As of 4.3 it can be [[DISPLAYED_ORDER]]. #[[PIC]] or #[[FMT]] could be used. #PIC and #FMT allow numeric data from a string to be used. For example: &#039;&#039;&#039;DISPLAYED_ORDER&#039;&#039;&#039; Indicates that the read operation is to not restore the data into it&#039;s original order before returning the results to the program (as of version 4.30). This reads the original row subscripts for all rows - in their present order - and only works with the ALL selection type.&lt;br /&gt;
&lt;br /&gt;
GRIDLINES makes LIST controls look like GRIDs with respect to the display of data (column and row separators).&lt;br /&gt;
 PRINT FIELDS &amp;quot;10,20,LIST 10/80,GRIDLINES&amp;quot;: 1 | 0 (on or off)&lt;br /&gt;
&lt;br /&gt;
The leading attribute values &amp;quot;^select&amp;quot; or &amp;quot;^deselect&amp;quot; may be specified to allow the pre-selection of GRID / LIST Elements: &lt;br /&gt;
 PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,^select ATTR&amp;quot;: (mat start, mat end, mat attr$)&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Fkey&#039;&#039;&#039; and &#039;&#039;&#039;Nowait&#039;&#039;&#039; parameters are optional. FKEY means that an FKEY event should be triggered when a selection is made by double clicking or pressing the Enter key, in navigation mode. Nowait simply means that it does not wait for user input.&lt;br /&gt;
&lt;br /&gt;
Following the ending quotation mark, a colon precedes the name of the I/O List.&lt;br /&gt;
&lt;br /&gt;
====DISPLAYED ORDER &#039;&#039;&#039;Read Qualifier&#039;&#039;&#039;==== &lt;br /&gt;
&lt;br /&gt;
As of 4.30, [[DISPLAYED ORDER]] - indicates that the read operation is to not restore the data into it&#039;s original order before returning the results to the program, for example:&lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, ROWSUB, ALL, DISPLAYED_ORDER, NOWAIT&amp;quot;: numeric-array &lt;br /&gt;
&lt;br /&gt;
This reads the original row subscripts for all rows in their present order. This qualifier works only with the ALL selection type. It may be used in conjunction with other qualifiers such as FKEY.&lt;br /&gt;
&lt;br /&gt;
==== Examples  ====&lt;br /&gt;
&lt;br /&gt;
===== LIST  =====&lt;br /&gt;
&lt;br /&gt;
 00210 INPUT FIELDS &amp;quot;10,20,LIST 10/80,ROWCNT,SEL,FKEY&amp;quot;: avail_rows&amp;amp;nbsp;! selected row cnt&lt;br /&gt;
 00220&amp;amp;nbsp;! next INPUT operation does not wait for operator&lt;br /&gt;
 00230 MAT subscr(avail_rows)         &amp;amp;nbsp;! redimension with number of selected rows&lt;br /&gt;
 00240 INPUT FIELDS &amp;quot;10,20,LIST 10/80,ROWSUB,SEL,NOWAIT&amp;quot;: MAT subscr&amp;amp;nbsp;! read subscripts&lt;br /&gt;
&lt;br /&gt;
===== Uniform GRID  =====&lt;br /&gt;
Contains one data array and multiple columns&lt;br /&gt;
&lt;br /&gt;
 00210 INPUT FIELDS &amp;quot;10,20,GRID 10/80,CNT,CHG&amp;quot;: cells     &amp;amp;nbsp;! # of changed cells&lt;br /&gt;
 00220 MAT subscr(cells)                                        &amp;amp;nbsp;! redimension&lt;br /&gt;
 00230 INPUT FIELDS &amp;quot;10,20,GRID 10/80,SUB,CHG,NOWAIT&amp;quot;: MAT subscr&amp;amp;nbsp;! read subscripts&lt;br /&gt;
 00240 MAT data$(cells)                                         &amp;amp;nbsp;! redimension&lt;br /&gt;
 00250 INPUT FIELDS &amp;quot;10,20,GRID 10/80,CELL,CHG,NOWAIT&amp;quot;: MAT data$&amp;amp;nbsp;! read changes&lt;br /&gt;
&lt;br /&gt;
===== Row Oriented GRID  =====&lt;br /&gt;
 00210 INPUT FIELDS &amp;quot;10,20,GRID 10/80,ROWCNT,CHG&amp;quot;: rows  &amp;amp;nbsp;! # of changed rows&lt;br /&gt;
 00220 MAT subscr(rows)                                  &amp;amp;nbsp;! redimension&lt;br /&gt;
 00230 INPUT FIELDS &amp;quot;10,20,GRID 10/80,ROWSUB,CHG,NOWAIT&amp;quot;: MAT subscr&amp;amp;nbsp;! read subscripts&lt;br /&gt;
 00240 MAT NAME$(rows)&amp;amp;nbsp;: MAT CITY$(rows)&amp;amp;nbsp;: MAT AGE(rows)&amp;amp;nbsp;: MAT WEIGHT(rows)&amp;amp;nbsp;! redimension&lt;br /&gt;
 00250 INPUT FIELDS &amp;quot;10,20,GRID 10/80,ROW,CHG,NOWAIT&amp;quot;: (MAT NAME$, MAT CITY$,MAT AGE, MAT WEIGHT)  &amp;amp;nbsp;! read changed rows&lt;br /&gt;
&lt;br /&gt;
This brings us to the question of what is to be done with the information after it has been read. If it is to be stored in a file, then we should have included a hidden column with master file record numbers of the data in each row. This would support looping through the input array and rewriting the changed data. &lt;br /&gt;
&lt;br /&gt;
While LIST subscripts are expressed in terms of rows, GRID subscripts may be either. In a four column five row GRID, the cell at row three column two has a subscript of ten.&lt;br /&gt;
&lt;br /&gt;
==== Cell Subscript Values of a 5 x 4 GRID  ====&lt;br /&gt;
&lt;br /&gt;
 1   2   3   4&lt;br /&gt;
 5   6   7   8&lt;br /&gt;
 9  10  11  12&lt;br /&gt;
 13 14  15  16&lt;br /&gt;
 17 18  19  20&lt;br /&gt;
&lt;br /&gt;
==== Sample Program====&lt;br /&gt;
The following example shows use of LIST and GRID controls. There are seven parts in this program. &lt;br /&gt;
&lt;br /&gt;
The first part creates a LIST with 2 columns and 3 rows. On lines 300 - 500, column headings, widths, and form specifications are assigned to the corresponding matrices. Lines 600 and 700 place data into the matrices to be printed in the LIST. The HEADERS operation on line 800 sets the column headings, widths and form specs. Line 900 populates the LIST by row, which is the default. &lt;br /&gt;
&lt;br /&gt;
 00100 dim HEADINGS$(2), WIDTHS(2), FORMS$(2), NAMES$(3)*28, CITIES$(3)*18, DATA$(1)*80, SUBSCR(1)&lt;br /&gt;
 00200 print NEWPAGE&lt;br /&gt;
 00300 let HEADINGS$(1)=&amp;quot;Name&amp;quot;: let HEADINGS$(2)=&amp;quot;City&amp;quot;&lt;br /&gt;
 00400 let WIDTHS(1)=30&amp;amp;nbsp;: let WIDTHS(2)=20&lt;br /&gt;
 00500 let FORMS$(1)=&amp;quot;CC 28&amp;quot;&amp;amp;nbsp;: let FORMS$(2)=&amp;quot;CC 18&amp;quot;&lt;br /&gt;
 00600 let NAMES$(1)=&amp;quot;Stalin&amp;quot;&amp;amp;nbsp;: let NAMES$(2)=&amp;quot;Napoleon&amp;quot;&amp;amp;nbsp;: let NAMES$(3)=&amp;quot;Roosevelt&amp;quot;&lt;br /&gt;
 00700 let CITIES$(1)=&amp;quot;Moscow&amp;quot;&amp;amp;nbsp;: let CITIES$(2)=&amp;quot;Paris&amp;quot;&amp;amp;nbsp;: let CITIES$(3)=&amp;quot;Washington&amp;quot;&lt;br /&gt;
 00800 print fields &amp;quot;1,1,list 8/60,headers&amp;quot;: (MAT HEADINGS$,MAT WIDTHS,MAT FORMS$)&lt;br /&gt;
 00900 print fields &amp;quot;1,1,list 8/60,=R&amp;quot;: (MAT NAMES$,MAT CITIES$)&lt;br /&gt;
 01000 print fields &amp;quot;9,1,C 50&amp;quot;&amp;amp;nbsp;: &amp;quot;Press enter to insert at the end of list&amp;quot;&lt;br /&gt;
 01100 let KSTAT$(1)&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output1.jpg]] &lt;br /&gt;
&lt;br /&gt;
The second part of the program demonstrates the use of the primary flag +, which adds to the end of any previously populated data. Line 01200 redimensions matrices NAMES$ and CITIES$ to allow room for one extra item in each of them. Line 01300 places new data into the matrices to be printed in the LIST.&amp;lt;br&amp;gt; Line 01400 adds the new data to the LIST. &lt;br /&gt;
&lt;br /&gt;
 01200 mat NAMES$(UDIM(NAMES$)+1)&amp;amp;nbsp;: mat CITIES$(UDIM(CITIES$)+1)&lt;br /&gt;
 01300 let NAMES$(4)=&amp;quot;Churchill&amp;quot;&amp;amp;nbsp;: let CITIES$(4)=&amp;quot;London&amp;quot;&lt;br /&gt;
 01400 print fields &amp;quot;1,1,list 8/60,+&amp;quot;: (MAT NAMES$(4:4),MAT CITIES$(4:4))&lt;br /&gt;
 01500 print fields &amp;quot;9,1,C 50&amp;quot;&amp;amp;nbsp;: &amp;quot;Select rows to be read into a matrix&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output2.jpg]] &lt;br /&gt;
&lt;br /&gt;
The third part of the program demonstrates use of read types ROWSUB and ROWCNT and selection type SEL. Line 1600 inputs the number of selected rows into AVAIL_ROWS. The user may select rows using the mouse or the keyboard and SHIFT and CTRL keys. Line 1700 redimensions matrix SUBSCR to the number of selected rows. Line 1800 inputs the subscripts of the selected rows into matrix SUBSCR. Line 1900 performs a HEADERS operation for a new LIST using the same matrices as were used in the previous LIST. Line 2000 populates the first row of the new LIST with the data from the first selected row from the previous LIST using the primary flag =. If user selects more than one row, then lines 2100 - 2500 add the data from the selected rows using the primary flag +. &lt;br /&gt;
&lt;br /&gt;
 01600 input fields &amp;quot;1,1,list 8/60,ROWCNT,SEL&amp;quot;: AVAIL_ROWS&lt;br /&gt;
 01700 mat SUBSCR(AVAIL_ROWS)&lt;br /&gt;
 01800 input fields &amp;quot;1,1,list 8/60,rowsub,sel,nowait&amp;quot;: MAT SUBSCR&lt;br /&gt;
 01900 print fields &amp;quot;12,1,list 8/60,headers&amp;quot;: (MAT HEADINGS$,MAT WIDTHS,MAT FORMS$)&lt;br /&gt;
 02000 print fields &amp;quot;12,1,list 8/60,=&amp;quot;: (MAT NAMES$(SUBSCR(1):SUBSCR(1)),MAT CITIES$(SUBSCR(1):SUBSCR(1)))&lt;br /&gt;
 02100 if UDIM(SUBSCR) &amp;amp;gt; 1 then&lt;br /&gt;
 02200   for I = 2 to UDIM(SUBSCR)&lt;br /&gt;
 02300     print fields &amp;quot;12,1,list 8/60,+&amp;quot;: ( MAT NAMES$(SUBSCR(I):SUBSCR(I)),MAT CITIES$(SUBSCR(I):SUBSCR(I)))&lt;br /&gt;
 02400   next I&lt;br /&gt;
 02500 end if&lt;br /&gt;
 02600 print fields &amp;quot;9,1,C 50&amp;quot;&amp;amp;nbsp;: &amp;quot;Press enter to insert at beginning of list&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output3.jpg]] &lt;br /&gt;
&lt;br /&gt;
The fourth part of the program demonstrates the use of the primary flag -, which inserts in the beginning of any previously populated data. Line 2800 redimensions matrices NAMES$ and CITIES$ to allow room for one extra item in each of them. Line 2900 places new data into the matrices to be printed in the LIST. Line 3000 adds the new data to the beginning of the LIST ahead of previously populated data. &lt;br /&gt;
&lt;br /&gt;
 02700 let KSTAT$(1)&lt;br /&gt;
 02800 mat NAMES$(UDIM(NAMES$)+1): mat CITIES$(UDIM(CITIES$)+1)&lt;br /&gt;
 02900 let NAMES$(5)=&amp;quot;Castro&amp;quot;&amp;amp;nbsp;:! let CITIES$(5)=&amp;quot;Havana&amp;quot;&lt;br /&gt;
 03000 print fields &amp;quot;1,1,list 8/60,-&amp;quot;: (MAT NAMES$(5:5),MAT CITIES$(5:5))&lt;br /&gt;
 03100 print fields &amp;quot;9,1,C 60&amp;quot;&amp;amp;nbsp;: &amp;quot;Press enter to populate list by column&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output4.jpg]] &lt;br /&gt;
&lt;br /&gt;
The fifth part of the program, more specifically, Line 3300, demonstrates the use of the secondary flag C to populate the LIST by column. The primary flag = is also used in order to replace any previously populated data. &lt;br /&gt;
&lt;br /&gt;
 03200 let KSTAT$(1)&lt;br /&gt;
 03300 print fields &amp;quot;1,1,list 8/60,=C&amp;quot;: (MAT NAMES$,MAT CITIES$)&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output5.jpg]] &lt;br /&gt;
&lt;br /&gt;
The sixth part of the program creates a GRID. The HEADERS operation on line 3600 uses the same HEADINGS$, WIDTHS, and FORMS$ as the previously constructed LISTs. Line 3700 sets CURFLD to be on the sixth cell of the GRID (this is discussed in the next section). Line 3800 populates the GRID. The user may change the contents of the cells. &lt;br /&gt;
&lt;br /&gt;
 03400 print fields &amp;quot;23,1,C 50&amp;quot;&amp;amp;nbsp;: &amp;quot;Press enter to continue&amp;quot;: let KSTAT$(1)&lt;br /&gt;
 03500 print NEWPAGE&lt;br /&gt;
 03600 print fields &amp;quot;1,1,grid 8/60,headers&amp;quot;: (MAT HEADINGS$,MAT WIDTHS,MAT FORMS$)&lt;br /&gt;
 03700 let CURFLD (1,6)&lt;br /&gt;
 03800 print fields &amp;quot;1,1,grid 8/60,=&amp;quot;: (MAT NAMES$,MAT CITIES$)&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output6.jpg]] &lt;br /&gt;
&lt;br /&gt;
The seventh part of the program demonstrates the use of read types CNT, CELL, and SUB and selection type CHG. Line 3900 counts the number of changed cells and inputs that number into variable CELLS. Line 4000 redimensions the matrix SUBSCR to the number of changed cells. Line 4100 inputs the changed cells into SUBSCR. Line 4200 redimensions the matrix DATA$.  Line 4300 inputs the subscripts of the changed cells into matrix DATA$. Line 4400 prints DATA$. &lt;br /&gt;
&lt;br /&gt;
 03900 input fields &amp;quot;1,1,grid 8/60,cnt,chg&amp;quot;: CELLS&lt;br /&gt;
 04000 mat SUBSCR(CELLS)&lt;br /&gt;
 04100 input fields &amp;quot;1,1,grid 8/60,sub,chg,nowait&amp;quot;: MAT SUBSCR&lt;br /&gt;
 04200 mat DATA$(CELLS)&lt;br /&gt;
 04300 input fields &amp;quot;1,1,grid 8/60,cell,chg,nowait&amp;quot;: MAT DATA$&lt;br /&gt;
 04400 print MAT DATA$&lt;br /&gt;
&lt;br /&gt;
===== Output  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output6b.jpg]]&lt;br /&gt;
&lt;br /&gt;
===== Output of line 04400  =====&lt;br /&gt;
&lt;br /&gt;
[[Image:Output7.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Displaying a List or Grid (Output Operations) ===&lt;br /&gt;
[[file:Grid2.png|900px]]&lt;br /&gt;
&lt;br /&gt;
To display a listview or a grid, you must set the headers first, using a special PRINT FIELDS operation.&lt;br /&gt;
&lt;br /&gt;
====HEADERS====&lt;br /&gt;
The HEADERS operation sets the column headings and widths. The corresponding input/output list value must be a parenthesized group of three arrays, for example: &lt;br /&gt;
&lt;br /&gt;
 00250 PRINT FIELDS &amp;quot;10,20,LIST 10/80,HEADERS&amp;quot;: (MAT HEADINGS$, MAT WIDTHS, MAT FIELD_FORMS$)&lt;br /&gt;
      - or -&lt;br /&gt;
 00250 PRINT FIELDS &amp;quot;10,20,GRID 10/80,HEADERS,[hdrs],1520&amp;quot;: (MAT HEADINGS$, MAT WIDTHS,MAT FIELD_FORMS$)&lt;br /&gt;
&lt;br /&gt;
The [hdrs] notation refers to an optional CONFIG ATTRIBUTE [HDRS] specification for setting the appearance of the header row. In this case the [] brackets are required. &lt;br /&gt;
&lt;br /&gt;
If a function key value (e.g. 1520) is given then when the control is not active, it may be clicked to trigger the specified interrupt similar to any other hot control. A function key interrupt is also triggered by double clicking during an Input operation. &lt;br /&gt;
&lt;br /&gt;
MAT HEADINGS$ Contains the column titles that will be displayed at the top of each column. The font, color and shading of these titles can be set through the [HDRS] or similar substitution attribute. &lt;br /&gt;
&lt;br /&gt;
MAT WIDTHS specifies DISPLAYED Column Widths and is expressed as the number of character positions occupied by each column. Scrollbars are provided as needed to honor overall control size specified in the FIELDS specification. &lt;br /&gt;
&lt;br /&gt;
For example, if four columns are specified and the widths are given as 10, 15, 10 and 5, then the 2D control occupies 40 character positions (plus a little for the column separators) irrespective of the number of columns specified for the display area. If needed, scroll bars are used to display wider controls within the displayed area. &lt;br /&gt;
&lt;br /&gt;
Displayed widths of zero characters are allowed. This enables the use of hidden columns for storing things like record numbers and record keys. &lt;br /&gt;
&lt;br /&gt;
MAT FIELD_FORMS$ provides the BR FORM for each column. e.g. C 15 stipulates a maximum field capacity of 15. The actual displayed length is a function of the grid size and the column relative width. &lt;br /&gt;
&lt;br /&gt;
The field form array elements may also include a comma followed by leading field attributes (e.g. color) pertaining to the column.  &lt;br /&gt;
&lt;br /&gt;
The number of columns must be set with HEADERS prior to Populating a control (loading data into it).&lt;br /&gt;
&lt;br /&gt;
====MASKing====&lt;br /&gt;
&lt;br /&gt;
As of 4.3, LIST and GRID support the MASK operation, both in READs and Populating, as seen in this section. For example:&lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;row,col,LIST rows/cols,MASK&amp;quot; :  mask_array&lt;br /&gt;
&lt;br /&gt;
This restricts the rows (for both LIST and GRID) previously displayed to those corresponding to a “true” value in mask_array. A true value is represented in a numeric array as a value greater than zero. Negative values are not allowed in mask arrays. A string mask array may also be used with “T” and “F” values. The MASK stays in effect until 1) a new MASK is specified or 2) the contents of the control are changed with PRINT ( &amp;lt;nowiki&amp;gt;=, +, -,&amp;lt;/nowiki&amp;gt; see primary flags below).  Also, the mask array affects only the user presentation, not the result set. &lt;br /&gt;
&lt;br /&gt;
====Populating====&lt;br /&gt;
&lt;br /&gt;
The populate operation loads data into the control. In the following example four columns are loaded: &lt;br /&gt;
&lt;br /&gt;
 03010 PRINT FIELDS &amp;quot;10,20,LIST 10/80, =&amp;quot;: (MAT NAME$, MAT CITY$,MAT AGE, MAT WEIGHT)&lt;br /&gt;
      - or -&lt;br /&gt;
 03020 PRINT FIELDS &amp;quot;10,20,GRID 10/80, =&amp;quot;: (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
In this example, the fourth element of the HEADERS FIELD_FORM$ array (above) could specify rounding of WEIGHT to two decimal places. If an fkey value is specified, then double-clicking (or single clicking if S is specified) a cell will generate the specified fkey interrupt. &lt;br /&gt;
&lt;br /&gt;
Permissible leading attribute values are:&lt;br /&gt;
&lt;br /&gt;
===== Primary Flags  =====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;=&#039;&#039;&#039; &lt;br /&gt;
| Replace any previous data&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;+&#039;&#039;&#039; &lt;br /&gt;
| Add to any previously populated data (this allows loading in chunks)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;-&#039;&#039;&#039; &lt;br /&gt;
| Insert data ahead of previously populated data (4.16+)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Secondary Flags  ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;R&#039;&#039;&#039; &lt;br /&gt;
| Load one row at a time (the default - use grouped IO parens)&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;C&#039;&#039;&#039; &lt;br /&gt;
| Load one column at a time - This is for loading multiple columns of the same data type&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;L&#039;&#039;&#039; &lt;br /&gt;
| Provide the FKEY (see INPUT below) or Enter interrupt if the user presses up arrow or page up in the first field, or down arrow or page down in the last field. Note that this is not specified in the individual field leading attributes.&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;S&#039;&#039;&#039; &lt;br /&gt;
| Single click to activate an Enter or FKEY event (otherwise a double click is required) (4.17+)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; Note that the following example will NOT work- &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT FIELDS &amp;quot;10,20,LIST 10/80,=C&amp;quot;: MAT NAME$,MAT CITY$,MAT AGE,MAT WEIGHT&lt;br /&gt;
&lt;br /&gt;
The reason is that only MAT NAME$ will reach the list. MAT CITY$, MAT AGE and MAT WEIGHT will be associated with subsequent fields. Multiple arrays provided to a single control must be grouped with parentheses. &lt;br /&gt;
&lt;br /&gt;
Populating a two-dimensional object by row with grouped IO means NAME$(1) will go into (1,1), AGE(1) will go into (1,2) and WGT(1) will go into (1,3) and so on. If a single array (MAT DATA$) is specified instead of a group, MAT DATA$ is applied horizontally instead of vertically. So DATA$(1) - DATA$(3) will be the first row and DATA$(4) - DATA$(6) will be the next row and so on. &lt;br /&gt;
&lt;br /&gt;
Populating a two dimensional grid by column with an array named DATA$ means that DATA$(1) goes in (1,1) and DATA$(2) goes in (2,1) and DATA$(3) goes in (3,1). Therefore the first however many values of DATA refer to the first column and the second however many values of DATA refer to the second column. So if there are 3 columns and UDIM(DATA$) = 90 then DATA$(1)-DATA$(30) is the first column, and DATA$(31) - DATA$(60) is the second column and DATA$(61) - DATA$(90) is the last column. &lt;br /&gt;
&lt;br /&gt;
For example, using the following information, each example demonstrates how the grid will be filled:&lt;br /&gt;
&lt;br /&gt;
MAT NAME$ = George, Peter, Tom &lt;br /&gt;
&lt;br /&gt;
MAT CITY$ = Dallas, Detroit, Denver &lt;br /&gt;
&lt;br /&gt;
MAT AGE$ = 42, 23, 35 &lt;br /&gt;
&lt;br /&gt;
MAT WEIGHT$ = 180, 212, 193 &lt;br /&gt;
&lt;br /&gt;
 00200 PRINT FIELDS &amp;quot;10,20,GRID 10/80, =&amp;quot;: (MAT NAME$, MAT CITY$,MAT AGE$, MAT WEIGHT$)&lt;br /&gt;
&lt;br /&gt;
Peter, Detroit, 23, 212 &lt;br /&gt;
&lt;br /&gt;
Tom, Denver, 35, 193 &lt;br /&gt;
&lt;br /&gt;
 00200 PRINT FIELDS &amp;quot;10,20,GRID 10/80, =C&amp;quot;: (MAT NAME$, MAT CITY$,MAT AGE$, MAT WEIGHT$)&lt;br /&gt;
&lt;br /&gt;
Dallas, Detroit, Denver &lt;br /&gt;
&lt;br /&gt;
42, 23, 35 &lt;br /&gt;
&lt;br /&gt;
180, 212, 193 &lt;br /&gt;
&lt;br /&gt;
As you can see using C with grouped arrays is counter-intuitive and doesn&#039;t fit well. C is most useful with a single array that should be loaded vertically down several columns. &lt;br /&gt;
&lt;br /&gt;
===== Grid Validation  =====&lt;br /&gt;
&lt;br /&gt;
GRIDs are now validated as each cell is exited instead of when control is passed to the BR program after all data is entered.&lt;br /&gt;
&lt;br /&gt;
===== Color and Font changes in Cells  =====&lt;br /&gt;
&lt;br /&gt;
The attributes that determine font, color and style in each cell can be set for an entire column by including these parameters in the heading FORM array. Individual cells can then be changed using a PRINT statement. &lt;br /&gt;
&lt;br /&gt;
The format of the print statement is &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT #WINNO, fields &amp;quot;2,2,LIST 10/60,ATTR&amp;quot;:(mat start, mat end, mat attribute$)&lt;br /&gt;
&lt;br /&gt;
With the following parameter descriptions: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;mat start&#039;&#039;&#039; &lt;br /&gt;
| contains the cell number(s) where the attribute chain begins,&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;mat end&#039;&#039;&#039; &lt;br /&gt;
| contains the last cell number where the attribute applies&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| width=&amp;quot;10%&amp;quot; | &#039;&#039;&#039;mat attribute$&#039;&#039;&#039; &lt;br /&gt;
| contains the attribute specification that should be applied to the cell range(s) specified.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the 2d control is a GRID, then mat Start and mat End refer to starting and ending Cell Numbers. If the 2d control is a listview, then mat Start and mat End refer to starting and ending Row Numbers. &lt;br /&gt;
&lt;br /&gt;
The attributes specified for any COLUMN can be overridden on a cell basis by specifying the starting cell number, ending cell number, and the overriding attributes in three arrays that are printed to the grid window with the same grid specificatoins and the key word &amp;quot;ATTR&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
 02420 PRINT #BLISTWIN,FIELDS BLISTSPEC$&amp;amp;amp;&amp;quot;,ATTR&amp;quot;: (MAT BROWS,MAT BROWE,MAT BATT$)&lt;br /&gt;
&lt;br /&gt;
In the above example, BLISTWIN is the window number, BLISTSPEC$ is the grid specification (&amp;quot;GRID 10/40&amp;quot; for example), BROWS is an array holding the starting cell number, BROWE is an array holding the ending cell number, and BATT$ is an array holding the overriding attributes. In a list the attributes of the first cell in the row controls the appearance of the entire row.&lt;br /&gt;
&lt;br /&gt;
 01500 PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,ATTR&amp;quot;: (mat start, mat end, mat attr$)&lt;br /&gt;
&lt;br /&gt;
The above example overrides the attributes of a range of cells/rows for a GRID/LIST display. This allows you to shade or otherwise alter the display of a range of cells / rows in a 2D control.&lt;br /&gt;
&lt;br /&gt;
====Aggregate Sorting====&lt;br /&gt;
BR supports aggregated sorting for LISTs and GRIDs. This means when clicking &lt;br /&gt;
on various column headings or programmatically sorting columns, fields of &lt;br /&gt;
equal values retain their previous order within their new groupings (4.2).&lt;br /&gt;
&lt;br /&gt;
==== Numeric Column Sorting  ====&lt;br /&gt;
&lt;br /&gt;
2D controls now facilitate numeric column sorting. This works well in conjunction with the new [[Date (Format Specification)|DATE]] field format (see release notes [[4.16]]) where the data is stored as day of century, but is displayed as a formatted date. It also works with all numeric columns.&lt;br /&gt;
&lt;br /&gt;
If a listview columns form spec if given as DATE(mm/dd/ccyy), for example, then any time that column is sorted, either as a result of the user clicking on the column heading, or the program giving the sort command (shown below), the dates are properly sorted even though they&#039;re displayed as mm/dd/ccyy. For this to work, the data has to be given in the julian days format, see the [[DAYS]] function for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In versions 4.2 and higher the syntax for sorting a listview is: &lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column number }&lt;br /&gt;
&lt;br /&gt;
To sort in reverse order, sort the column twice:&lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column number }&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { same column number }&lt;br /&gt;
&lt;br /&gt;
This has been extended in version 4.3 to allow a numeric array instead of a scalar. If an array is given, it is assumed to be in the same format that SORT_ORDER returns. The new format is: &lt;br /&gt;
&lt;br /&gt;
    PRINT FIELDS &amp;quot;nn,nn,GRID 10/40,SORT&amp;quot;: { column-number | numeric-array }&lt;br /&gt;
&lt;br /&gt;
Where the numeric-array has one element for each column left to right. BR will resort the columns in the requested order. &lt;br /&gt;
&lt;br /&gt;
The numeric array values indicating the order of column sorting to be performed do not need to exactly match the standard format. e.g Fractions are allowed, the values can fall within any range, and there does not need to be trailing zero elements for unsorted columns.&lt;br /&gt;
&lt;br /&gt;
==== NOSORT for Columns  ====&lt;br /&gt;
As of 4.2, the &#039;&#039;&#039;NoSort&#039;&#039;&#039; parameter is used to prevent users from sorting columns of a Grid or List. &lt;br /&gt;
&lt;br /&gt;
For the statement: &lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;10,20,GRID 10/80,HEADERS,[hdrs],1520&amp;quot;: (MAT HEADINGS$, MAT WIDTHS, MAT FIELD_FORMS$) &lt;br /&gt;
&lt;br /&gt;
The field attribute &amp;quot;^nosort&amp;quot; appearing in the MAT FIELD_FORM$ prevents the sorting of a grid or listview in response to the user clicking on the corresponding column header. This does not prevent programs from sorting on those columns.&lt;br /&gt;
&lt;br /&gt;
==== Range Input  ====&lt;br /&gt;
&lt;br /&gt;
The following examples are used in versions 4.3 and higher. In these examples BR will redimension the receiving arrays as needed: &lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, CELL, RANGE&amp;quot; :&lt;br /&gt;
             start, end, MAT Data$&lt;br /&gt;
&lt;br /&gt;
This reads the specified range of cells. BR redimensions MAT Data$ as needed. Note that CELL may now be used with LIST. Previously, LISTs were only addressable by row. &lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, ROW, RANGE&amp;quot; :&lt;br /&gt;
             (start:=7), (end:=11), ( MAT Array1$, MAT Array2, MAT Array3$ )&lt;br /&gt;
&lt;br /&gt;
This reads the cells in rows 7 through 11. The receiving arrays are re-dimensioned as appropriate. &lt;br /&gt;
&lt;br /&gt;
 INPUT FIELDS &amp;quot;row,col,GRID rows/cols, ROW, RANGE&amp;quot;:&lt;br /&gt;
             MAT start, MAT end, ( MAT Data1$, MAT Data2$, MAT Data3 )&lt;br /&gt;
&lt;br /&gt;
This reads one or more ranges of rows. &lt;br /&gt;
&lt;br /&gt;
A more detailed example of this is: &lt;br /&gt;
&lt;br /&gt;
 100 ! create and populate a LIST control &lt;br /&gt;
 200 MAT START(3) : MAT END(3)&lt;br /&gt;
 210 READ MAT START, MAT END&lt;br /&gt;
 220 DATA 7,21,33&lt;br /&gt;
 230 DATA 11,21,38&lt;br /&gt;
 240 INPUT FIELDS &amp;quot;row,col,LIST rows/cols, ROW, RANGE&amp;quot;&amp;amp;nbsp;: MAT START,&lt;br /&gt;
            MAT END, ( MAT Array1$, MAT Array2, MAT Array3$ )&lt;br /&gt;
&lt;br /&gt;
This reads 12 rows of data ( row 7-11, row 21 and rows 33-38 ). &lt;br /&gt;
&lt;br /&gt;
==== Range Output  ====&lt;br /&gt;
&lt;br /&gt;
The following examples are valid for versions [[4.3]] and higher. By default, RANGE output refers to rows. The special keyword CELL_RANGE is used to denote the specification of cell ranges. Additionally, the use of scalars versus arrays for start and end values determines important characteristics of the output process. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; Using Scalars For Range Specification &lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;7,8,GRID 10/75, RANGE&amp;quot;: start, end, MAT Data$&lt;br /&gt;
&lt;br /&gt;
This replaces the values in rows numbered &#039;start&#039; through &#039;end&#039; with the data in MAT Data$. The size of MAT Data$ must be a multiple of the number of columns in the GRID or an error is generated. &lt;br /&gt;
&lt;br /&gt;
 PRINT FIELDS &amp;quot;7,8,LIST 10/75, RANGE&amp;quot;: start, end, (MAT NAME$,                                   MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
This replaces the values in ROWs numbered &#039;start&#039; through &#039;end&#039; with the data from MATs NAME$, CITY$, AGE and WEIGHT. The data arrays must all be dimensioned the same. &lt;br /&gt;
&lt;br /&gt;
==== Insertion and Deletion with RANGE ====&lt;br /&gt;
&lt;br /&gt;
The number of rows being output do not need to match the number of rows being replaced. To delete a range of rows, output one or more grouped arrays with zero elements. &lt;br /&gt;
&lt;br /&gt;
The following examples are valid for versions 4.3 and higher. Using the following statement, various scenarios are described. &lt;br /&gt;
&lt;br /&gt;
  PRINT FIELDS &amp;quot;7,8,LIST 10/75, RANGE&amp;quot;: start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
 start=7, end=11, and the arrays have been DIMed to nine elements&lt;br /&gt;
 Result- Nine rows replace five, and the total content of the control is expanded by 4 rows.&lt;br /&gt;
&lt;br /&gt;
 start=7, end=11, and the arrays are DIMed to zero elements&lt;br /&gt;
 Result- Five rows are deleted, and the total size of the control is reduced by 5 rows.&lt;br /&gt;
&lt;br /&gt;
 start=7, end=0 (anything less than 7), and the arrays are DIMed to support three rows&lt;br /&gt;
 Result- Three rows are inserted ahead of row seven and the total content of the control is expanded by three rows&lt;br /&gt;
&lt;br /&gt;
 start=5000, end={any value}, the control only has 482 rows, and the source arrays are DIMed to support eleven rows&lt;br /&gt;
 Result- Eleven rows are appended to the end of the control and become rows 483 through 493.&lt;br /&gt;
&lt;br /&gt;
==== Outputting Ranges of Cells  ====&lt;br /&gt;
&lt;br /&gt;
The following examples are valid for versions 4.3 and higher. &lt;br /&gt;
&lt;br /&gt;
Ranges of cells may be output in conjunction with the CELL_RANGE keyword. &lt;br /&gt;
&lt;br /&gt;
  PRINT FIELDS &amp;quot;7,8,LIST 10/75, CELL_RANGE&amp;quot;: start, end, (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
                                - or -&lt;br /&gt;
&lt;br /&gt;
  PRINT FIELDS &amp;quot;7,8,GRID 10/75, CELL_RANGE&amp;quot;: start, end, MAT Data$&lt;br /&gt;
&lt;br /&gt;
In this case, start and end specify cells instead of rows. If insertion or deletion is indicated by dimensioning the data arrays to greater or fewer elements than are being replaced, then the data must be a multiple of the number of columns. Insertion and deletion is only valid in terms of rows, even when cell subscripts are used to specify ranges. In such cases, if the cell subscripts are not on row boundaries, an error is generated. &lt;br /&gt;
&lt;br /&gt;
  PRINT FIELDS &amp;quot;7,8,GRID 10/75, CELL_RANGE&amp;quot;: start, start, Data$&lt;br /&gt;
&lt;br /&gt;
In this example, the value in one cell is replaced with the content of a scalar.&lt;br /&gt;
&lt;br /&gt;
==== Using Arrays For Range Specification  ====&lt;br /&gt;
&lt;br /&gt;
If the start and end specifications are array denoting multiple ranges, there must be a one to one correspondence between the number of rows specified and those in the data. This method implies replacement only and insertion or deletion is not allowed. &lt;br /&gt;
&lt;br /&gt;
The data flow that this feature was designed to support is one where the user is presented with a LIST or GRID where multiple rows have been either selected or changed before returning control to the program and the program is responding by updating something on those rows. &lt;br /&gt;
&lt;br /&gt;
The program begins by presenting a 2D control to the user and reading the the control with type ROWSUB or SUB. Type SUB only works for GRIDs where all colmns have the same data type. Of course the subscripts are read into a numeric array which BR redimensions as appropriate. Then the program reads the changed or selected data with NOWAIT. (This resets the CHG flags in the control.) The program then changes either row (ROWSUB) or cell (SUB) data and outputs the results using the subscript array as both the start and end specification. Other scenarios are possible but this is the primary intended use. &lt;br /&gt;
&lt;br /&gt;
The following examples are valid for versions 4.3 and higher: &lt;br /&gt;
&lt;br /&gt;
  100 ! create and populate a GRID --&lt;br /&gt;
  200 INPUT FIELDS &amp;quot;row,col,GRID rows/cols,ROWSUB,CHG&amp;quot;: MAT Rowsubs&lt;br /&gt;
         (Reading subscripts does not reset the CHG flags in the control.)&lt;br /&gt;
  210 INPUT FIELDS &amp;quot;row,col,GRID rows/cols,ROW,CHG,NOWAIT&amp;quot;: ( MAT Data1$,&lt;br /&gt;
        MAT Data2, MAT Data3$ )&lt;br /&gt;
          BR redimensions the receiving arrays as needed.&lt;br /&gt;
         (Reading the data also resets the CHG flags in the control.)&lt;br /&gt;
&lt;br /&gt;
  220 ! process the changed rows now present in the data arrays --&lt;br /&gt;
  300 PRINT FIELDS &amp;quot;row,col,GRID rows/cols,RANGE&amp;quot;: MAT Rowsubs,&lt;br /&gt;
                   MAT Rowsubs, ( MAT Data1$, MAT Data2, MAT Data3$ )&lt;br /&gt;
&lt;br /&gt;
This outputs the updated rows. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Grid and List BR_VB Similarities  ====&lt;br /&gt;
Before introducing grids and lists in BR, similar effects could be achieved using BR_VB to work with Visual Basic. If you were familiar with BR_VB, the following notes may be of interest:&lt;br /&gt;
&lt;br /&gt;
Grid and list controls work like the BR_VB interface except headers now specify the form of each column and a new input type has been added: &lt;br /&gt;
&lt;br /&gt;
A multi column LISTview- &lt;br /&gt;
&lt;br /&gt;
 00100 PRINT FIELDS &amp;quot;10,20,LIST 10/80,HEADERS[,hdrs][,fkey]&amp;quot;: (MAT HEADINGS$, MAT WIDTHS, MAT FORMS$) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note-&#039;&#039;&#039; Widths are expressed in character positions, not percentages like they are in BR_VB. &lt;br /&gt;
&lt;br /&gt;
The populate operation- &lt;br /&gt;
&lt;br /&gt;
 00200 PRINT FIELDS &amp;quot;10,20,LIST 10/80,=&amp;quot;: (MAT NAME$, MAT CITY$, MAT AGE, MAT WEIGHT)&lt;br /&gt;
&lt;br /&gt;
Read-Ctl type: CNT (in place of CELLROWSUB) returns a single numeric value which is the number of subscripts available to read. In the case of grids, this is the number of cells. In the case of LISTviews, this is the number of rows. &lt;br /&gt;
&lt;br /&gt;
 00110 INPUT FIELDS &amp;quot;10,20,LIST 10/80,ROWCNT,SEL&amp;quot;: avail_rows&amp;amp;nbsp;! # of selected rows&lt;br /&gt;
 00120 MAT DATA$(3 * avail_rows)         &amp;amp;nbsp;! redimension.. 3 cols x selected rows&lt;br /&gt;
 00130 INPUT FIELDS &amp;quot;10,20,LIST 10/80,ROW,SEL,NOWAIT&amp;quot;: MAT DATA$&amp;amp;nbsp;! read rows&lt;br /&gt;
&lt;br /&gt;
====See Also: ====&lt;br /&gt;
[[Grids Tutorial]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Widget]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=SQL&amp;diff=10662</id>
		<title>SQL</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=SQL&amp;diff=10662"/>
		<updated>2015-10-05T20:52:10Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* OPEN statements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SQL manages data via a relational data management system. As of 4.3, BR includes several special ways of working together with SQL.&lt;br /&gt;
&lt;br /&gt;
====CONFIG DATABASE db-ref ODBC-MANAGER====&lt;br /&gt;
CONFIG [[DATABASE]] db-ref ODBC-MANAGER will invoke the ODBC Manager to define or identify a file DSN. Once this is done you can issue the command [[STATUS]] DATABASE –P to see the connect string that the ODBC Manager used to make the connection. Thereafter you can use that connect string to establish the connection to the database as follows:&lt;br /&gt;
&lt;br /&gt;
 CONFIG DATABASE db-ref  CONNECTSTRING=&amp;quot;Driver={Microsoft Access Driver (*.mdb)}DBQ=C:\inetpub\wwwroot\BegASP\Chapter.14\Contact.mdb&amp;quot;&lt;br /&gt;
            - or -&lt;br /&gt;
 CONFIG DATABASE db-ref  DSN=’dsn-ref ‘ &lt;br /&gt;
&lt;br /&gt;
;Additional Optional Parameters:&lt;br /&gt;
&lt;br /&gt;
 [, USER= department | LOGIN_NAME | ? ]&lt;br /&gt;
 [, {PASSWORD= dept-password | PASSWORDD=encrypted-passwd  | BR_PASSWORD | ? ]&lt;br /&gt;
&lt;br /&gt;
Where &#039;&#039;&#039;?&#039;&#039;&#039; indicates prompt and &#039;&#039;&#039;BR_PASSWORD&#039;&#039;&#039; indicates the password used during client login. If running the standard model (not client-server) then this is equivalent to &amp;quot;?&amp;quot;. &#039;&#039;&#039;encrypted-passwd&#039;&#039;&#039; is the DB password encrypted with the key stated in OPTION 66.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CONFIG DATABASE  MAX_COLUMN_WIDTH   nnnn&#039;&#039;&#039;&lt;br /&gt;
Some database column types are variable length. SQL requires advanced buffer allocation. This would unnecessarily tax the system if not restricted. This statement sets a maximum width for all columns. Memory is allocated to the minimum of (this amount or the column width). &amp;quot;nnnn&amp;quot; is the maximum column width. The default is 2000 characters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;CONFIG DATABASE CLEAR   { db-ref | ALL }&#039;&#039;&#039;&lt;br /&gt;
This will close the specified database or all open databases.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sample Connection Strings:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 Using a SQL Server /w SQL Login:&lt;br /&gt;
 CONFIG database db-ref connectstring=&amp;quot;DRIVER=SQL Server;SERVER=server;Initial Catalog=database;UID=username;PWD=password&amp;quot;&lt;br /&gt;
 db-ref is the database reference.&lt;br /&gt;
 server is the SQL Server [FQDN] or IP Address&lt;br /&gt;
 database is the [SQL Server Database] &lt;br /&gt;
 username is the [SQL Server User Name]&lt;br /&gt;
 password is the [SQL Server Password]&lt;br /&gt;
&lt;br /&gt;
 Using a SQL Server /w Windows Authentication:&lt;br /&gt;
 CONFIG database db-ref connectstring=&amp;quot;DRIVER=SQL Server;Initial Catalog=database;Persist Security Info=True;MultipleBC_TableResultSets=True; Database=database;SERVER=server;Login Name=username;Password=BR_PASSWORD&amp;quot;&lt;br /&gt;
 db-ref is the database reference.&lt;br /&gt;
 server is the SQL Server [FQDN] or IP Address&lt;br /&gt;
 database is the [SQL Server Database] &lt;br /&gt;
 username is the [SQL Server User Name]&lt;br /&gt;
 Note that BR_PASSWORD will use the users Active Directory password to connect to the SQL Server.&lt;br /&gt;
 Note that &amp;quot;SQL Server&amp;quot; is one of several choices for SQL Server, another choice would be SQL Server Native Client 11.0&lt;br /&gt;
&lt;br /&gt;
====OPEN statements====&lt;br /&gt;
&lt;br /&gt;
 OPEN #20: &amp;quot;DATABASE= db-ref&amp;quot;, SQL &amp;quot;sql-statement&amp;quot;, OUTIN&lt;br /&gt;
              - or -&lt;br /&gt;
 OPEN #20: &amp;quot;DATABASE= db-ref, Name= filename&amp;quot; , SQL, OUTIN&lt;br /&gt;
Where filename refers to a DISPLAY file containing a SQL statement that gets executed when a WRITE statement is processed.&lt;br /&gt;
&lt;br /&gt;
Example: &lt;br /&gt;
 OPEN #20: &amp;quot;DATABASE=MyData&amp;quot;,SQL &amp;quot;SELECT FILENO,BALANCE from MASTER WHERE FILENO=?&amp;quot;,OUTIN&lt;br /&gt;
&lt;br /&gt;
====Sequence of Operations====&lt;br /&gt;
#Begin processing with a WRITE statement.&lt;br /&gt;
#If the WRITE contains an IO list of values then it is used to populate the SQL before it is executed. In this process IO list values replace question marks positionally from left to right. These question marks only work with SQL arguments that refer to stored data. Question marks cannot be specified where SQL keywords or table column names appear. &lt;br /&gt;
#Resulting SQL may or may not produce a result set. If it does, the result set may be processed like a BR file opened RELATIVE. Some operations that use file positioning may be slow since the whole result set may not be in memory immediately. Simple sequential access should be fairly quick.&lt;br /&gt;
#Once SQL has been populated by an IOlist, it may be reused with the same values by issuing a WRITE with no IOlist.&lt;br /&gt;
#READ IOlist variable associations are positional with each READ accessing one row of values.&lt;br /&gt;
&lt;br /&gt;
===SQL Date Format Functions===&lt;br /&gt;
&lt;br /&gt;
 A$=SQL_DATE$(BR-date-string,&amp;quot;format-mask&amp;quot;)   ! format date for storage&lt;br /&gt;
 B$=BR_DATE$(SQL-date-string,&amp;quot;format-mask&amp;quot;)   ! unpack DB date value&lt;br /&gt;
&lt;br /&gt;
===SQL Table Interrogation===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ENV$(STATUS)&#039;&#039;&#039; has been extended to interrogate database connections and ODBC data sources. A program called ENVDB.BRS (listed below) has been written to demonstrate how this extension works and to show how to setup linkage to a database or ODBC data source. Run the program as is to bring up the Microsoft ODBC manager. Then select a data source and look at the output from the program. This will also show you how to get and use connect strings. In this example lines 1900 and 2000 accomplish the same open as line 1800 in my environment. &lt;br /&gt;
&lt;br /&gt;
Try it on your Windows workstation. As long as you have one or more ODBC drivers supported you can use it without having to install a database. You can even use it to interrogate Excel files because Microsoft provides an ODBC driver for that. &lt;br /&gt;
&lt;br /&gt;
A sample program to demonstrate database interrogation entry is:&lt;br /&gt;
 01000 ! Replace Envdb&lt;br /&gt;
 01100    dim DATABASES$(1)*100&lt;br /&gt;
 01200    dim DATABASE$*100&lt;br /&gt;
 01300    dim TABLES$(1)*100&lt;br /&gt;
 01400    dim TABLE$*100&lt;br /&gt;
 01500    dim COLUMNS$(1)*100&lt;br /&gt;
 01600    dim COLUMN$*100&lt;br /&gt;
 01700    dim C$*100,FLD1$*40,FLD2$*40,FLD3$*40,FLD4$*40&lt;br /&gt;
 01800    Execute &amp;quot;CONFIG database testdb odbc-manager&amp;quot;&lt;br /&gt;
 01900 !   Execute &amp;quot;CONFIG database testdb DSN=&#039;Accounts Payable&#039;&amp;quot;&lt;br /&gt;
 02000 !   Execute &amp;quot;CONFIG database testdb connectstring=&amp;quot;&amp;quot;DSN=Excel Files;DBQ=L:\orders\Beneficial PORCEL.xls;DefaultDir=L:\orders;DriverId=1046;MaxBufferSize=2048&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 02100    open #1: &amp;quot;name=envdb.txt,replace&amp;quot;,display,output &lt;br /&gt;
 02200 Dump_Table: ! ***** Dump Table Layout&lt;br /&gt;
 02300    let OUTFD = 1&lt;br /&gt;
 02400    let ENV$(&amp;quot;status.database.LIST&amp;quot;, MAT DATABASES$)  !List of db&#039;s&lt;br /&gt;
 02500    for DATABASE=1 to UDIM(DATABASES$)  !For each connected database&lt;br /&gt;
 02600       let DATABASE$=DATABASES$(DATABASE)&lt;br /&gt;
 02700       let FNSHOW_DATABASE(DATABASE$, &amp;quot;status.database.&amp;quot;&amp;amp;DATABASE$)&lt;br /&gt;
 02800    next DATABASE&lt;br /&gt;
 02900    end &lt;br /&gt;
 03000 ! &lt;br /&gt;
 03100    def FNSHOW_DATABASE(DATABASE$*100, ST_PREFIX$*100)&lt;br /&gt;
 03200       print #OUTFD: DATABASE$&lt;br /&gt;
 03300       let OUT_PREFIX$=CHR$(9)&lt;br /&gt;
 03400       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;DSN=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.DSN&amp;quot;)&lt;br /&gt;
 03500       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;CONNECTSTRING=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.CONNECTSTRING&amp;quot;)&lt;br /&gt;
 03600       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Tables:&amp;quot;&lt;br /&gt;
 03700       let ST_PREFIX$=ST_PREFIX$&amp;amp;&amp;quot;.TABLES&amp;quot;&lt;br /&gt;
 03800       let ENV$(ST_PREFIX$&amp;amp;&amp;quot;.LIST&amp;quot;, MAT TABLES$)&lt;br /&gt;
 03900       for TABLE = 1 to UDIM(MAT TABLES$)&lt;br /&gt;
 04000          let TABLE$=TABLES$(TABLE)&lt;br /&gt;
 04100          let FNSHOW_TABLE(TABLE$,ST_PREFIX$&amp;amp;&amp;quot;.&amp;quot;&amp;amp;TABLE$,OUT_PREFIX$&amp;amp;CHR$(9))&lt;br /&gt;
 04200       next TABLE&lt;br /&gt;
 04300    fnend &lt;br /&gt;
 04400 ! &lt;br /&gt;
 04500    def FNSHOW_TABLE(TABLE$*100, ST_PREFIX$*100, OUT_PREFIX$)&lt;br /&gt;
 04600       print #OUTFD: OUT_PREFIX$&amp;amp;TABLE$&lt;br /&gt;
 04700       let OUT_PREFIX$=OUT_PREFIX$&amp;amp;CHR$(9)&lt;br /&gt;
 04800       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Table remarks=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.REMARKS&amp;quot;)&lt;br /&gt;
 04900       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Table type=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.TYPE&amp;quot;)&lt;br /&gt;
 05000       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Columns:&amp;quot;&lt;br /&gt;
 05100       let ST_PREFIX$=ST_PREFIX$&amp;amp;&amp;quot;.COLUMNS&amp;quot;&lt;br /&gt;
 05200       let ENV$(ST_PREFIX$&amp;amp;&amp;quot;.LIST&amp;quot;, MAT COLUMNS$)&lt;br /&gt;
 05300       for COLUMN = 1 to UDIM(MAT COLUMNS$)&lt;br /&gt;
 05400          let COLUMN$=COLUMNS$(COLUMN)&lt;br /&gt;
 05500          let FNSHOW_COLUMN(COLUMN$, ST_PREFIX$&amp;amp;&amp;quot;.&amp;quot;&amp;amp;COLUMN$,OUT_PREFIX$&amp;amp;CHR$(9))&lt;br /&gt;
 05600       next COLUMN&lt;br /&gt;
 05700    fnend &lt;br /&gt;
 05800 ! &lt;br /&gt;
 05900    def FNSHOW_COLUMN(COLUMN$*100, ST_PREFIX$*100, OUT_PREFIX$)&lt;br /&gt;
 06000       print #OUTFD: OUT_PREFIX$&amp;amp;COLUMN$&lt;br /&gt;
 06100       let OUT_PREFIX$=OUT_PREFIX$&amp;amp;CHR$(9)&lt;br /&gt;
 06200       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Column type=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.TYPE&amp;quot;)&lt;br /&gt;
 06300       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Column length=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.LENGTH&amp;quot;)&lt;br /&gt;
 06400       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Column decimals=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.DECIMALS&amp;quot;)&lt;br /&gt;
 06500    fnend&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
For more information about &#039;&#039;&#039;SQL&#039;&#039;&#039; or &#039;&#039;&#039;Structured Query Language&#039;&#039;&#039; see [[Wikipedia:SQL]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Terminology]]&lt;br /&gt;
[[Category:SQL]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
	<entry>
		<id>https://brwiki2.brulescorp.com/brwiki2/index.php?title=SQL&amp;diff=10661</id>
		<title>SQL</title>
		<link rel="alternate" type="text/html" href="https://brwiki2.brulescorp.com/brwiki2/index.php?title=SQL&amp;diff=10661"/>
		<updated>2015-10-05T20:42:35Z</updated>

		<summary type="html">&lt;p&gt;Laura: /* CONFIG DATABASE db-ref ODBC-MANAGER */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SQL manages data via a relational data management system. As of 4.3, BR includes several special ways of working together with SQL.&lt;br /&gt;
&lt;br /&gt;
====CONFIG DATABASE db-ref ODBC-MANAGER====&lt;br /&gt;
CONFIG [[DATABASE]] db-ref ODBC-MANAGER will invoke the ODBC Manager to define or identify a file DSN. Once this is done you can issue the command [[STATUS]] DATABASE –P to see the connect string that the ODBC Manager used to make the connection. Thereafter you can use that connect string to establish the connection to the database as follows:&lt;br /&gt;
&lt;br /&gt;
 CONFIG DATABASE db-ref  CONNECTSTRING=&amp;quot;Driver={Microsoft Access Driver (*.mdb)}DBQ=C:\inetpub\wwwroot\BegASP\Chapter.14\Contact.mdb&amp;quot;&lt;br /&gt;
            - or -&lt;br /&gt;
 CONFIG DATABASE db-ref  DSN=’dsn-ref ‘ &lt;br /&gt;
&lt;br /&gt;
;Additional Optional Parameters:&lt;br /&gt;
&lt;br /&gt;
 [, USER= department | LOGIN_NAME | ? ]&lt;br /&gt;
 [, {PASSWORD= dept-password | PASSWORDD=encrypted-passwd  | BR_PASSWORD | ? ]&lt;br /&gt;
&lt;br /&gt;
Where &#039;&#039;&#039;?&#039;&#039;&#039; indicates prompt and &#039;&#039;&#039;BR_PASSWORD&#039;&#039;&#039; indicates the password used during client login. If running the standard model (not client-server) then this is equivalent to &amp;quot;?&amp;quot;. &#039;&#039;&#039;encrypted-passwd&#039;&#039;&#039; is the DB password encrypted with the key stated in OPTION 66.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CONFIG DATABASE  MAX_COLUMN_WIDTH   nnnn&#039;&#039;&#039;&lt;br /&gt;
Some database column types are variable length. SQL requires advanced buffer allocation. This would unnecessarily tax the system if not restricted. This statement sets a maximum width for all columns. Memory is allocated to the minimum of (this amount or the column width). &amp;quot;nnnn&amp;quot; is the maximum column width. The default is 2000 characters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;CONFIG DATABASE CLEAR   { db-ref | ALL }&#039;&#039;&#039;&lt;br /&gt;
This will close the specified database or all open databases.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sample Connection Strings:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 Using a SQL Server /w SQL Login:&lt;br /&gt;
 CONFIG database db-ref connectstring=&amp;quot;DRIVER=SQL Server;SERVER=server;Initial Catalog=database;UID=username;PWD=password&amp;quot;&lt;br /&gt;
 db-ref is the database reference.&lt;br /&gt;
 server is the SQL Server [FQDN] or IP Address&lt;br /&gt;
 database is the [SQL Server Database] &lt;br /&gt;
 username is the [SQL Server User Name]&lt;br /&gt;
 password is the [SQL Server Password]&lt;br /&gt;
&lt;br /&gt;
 Using a SQL Server /w Windows Authentication:&lt;br /&gt;
 CONFIG database db-ref connectstring=&amp;quot;DRIVER=SQL Server;Initial Catalog=database;Persist Security Info=True;MultipleBC_TableResultSets=True; Database=database;SERVER=server;Login Name=username;Password=BR_PASSWORD&amp;quot;&lt;br /&gt;
 db-ref is the database reference.&lt;br /&gt;
 server is the SQL Server [FQDN] or IP Address&lt;br /&gt;
 database is the [SQL Server Database] &lt;br /&gt;
 username is the [SQL Server User Name]&lt;br /&gt;
 Note that BR_PASSWORD will use the users Active Directory password to connect to the SQL Server.&lt;br /&gt;
 Note that &amp;quot;SQL Server&amp;quot; is one of several choices for SQL Server, another choice would be SQL Server Native Client 11.0&lt;br /&gt;
&lt;br /&gt;
====OPEN statements====&lt;br /&gt;
&lt;br /&gt;
 OPEN #20: &amp;quot;DATABASE= db-ref&amp;quot;, SQL &amp;quot;sql-statement&amp;quot;, OUTIN&lt;br /&gt;
              - or -&lt;br /&gt;
 OPEN #20: &amp;quot;DATABASE= db-ref, Name= filename&amp;quot; , SQL, OUTIN&lt;br /&gt;
Where filename refers to a DISPLAY file containing a SQL statement that gets executed when a WRITE statement is processed.&lt;br /&gt;
&lt;br /&gt;
====Sequence of Operations====&lt;br /&gt;
#Begin processing with a WRITE statement.&lt;br /&gt;
#If the WRITE contains an IO list of values then it is used to populate the SQL before it is executed. In this process IO list values replace question marks positionally from left to right. These question marks only work with SQL arguments that refer to stored data. Question marks cannot be specified where SQL keywords or table column names appear. &lt;br /&gt;
#Resulting SQL may or may not produce a result set. If it does, the result set may be processed like a BR file opened RELATIVE. Some operations that use file positioning may be slow since the whole result set may not be in memory immediately. Simple sequential access should be fairly quick.&lt;br /&gt;
#Once SQL has been populated by an IOlist, it may be reused with the same values by issuing a WRITE with no IOlist.&lt;br /&gt;
#READ IOlist variable associations are positional with each READ accessing one row of values.&lt;br /&gt;
&lt;br /&gt;
===SQL Date Format Functions===&lt;br /&gt;
&lt;br /&gt;
 A$=SQL_DATE$(BR-date-string,&amp;quot;format-mask&amp;quot;)   ! format date for storage&lt;br /&gt;
 B$=BR_DATE$(SQL-date-string,&amp;quot;format-mask&amp;quot;)   ! unpack DB date value&lt;br /&gt;
&lt;br /&gt;
===SQL Table Interrogation===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ENV$(STATUS)&#039;&#039;&#039; has been extended to interrogate database connections and ODBC data sources. A program called ENVDB.BRS (listed below) has been written to demonstrate how this extension works and to show how to setup linkage to a database or ODBC data source. Run the program as is to bring up the Microsoft ODBC manager. Then select a data source and look at the output from the program. This will also show you how to get and use connect strings. In this example lines 1900 and 2000 accomplish the same open as line 1800 in my environment. &lt;br /&gt;
&lt;br /&gt;
Try it on your Windows workstation. As long as you have one or more ODBC drivers supported you can use it without having to install a database. You can even use it to interrogate Excel files because Microsoft provides an ODBC driver for that. &lt;br /&gt;
&lt;br /&gt;
A sample program to demonstrate database interrogation entry is:&lt;br /&gt;
 01000 ! Replace Envdb&lt;br /&gt;
 01100    dim DATABASES$(1)*100&lt;br /&gt;
 01200    dim DATABASE$*100&lt;br /&gt;
 01300    dim TABLES$(1)*100&lt;br /&gt;
 01400    dim TABLE$*100&lt;br /&gt;
 01500    dim COLUMNS$(1)*100&lt;br /&gt;
 01600    dim COLUMN$*100&lt;br /&gt;
 01700    dim C$*100,FLD1$*40,FLD2$*40,FLD3$*40,FLD4$*40&lt;br /&gt;
 01800    Execute &amp;quot;CONFIG database testdb odbc-manager&amp;quot;&lt;br /&gt;
 01900 !   Execute &amp;quot;CONFIG database testdb DSN=&#039;Accounts Payable&#039;&amp;quot;&lt;br /&gt;
 02000 !   Execute &amp;quot;CONFIG database testdb connectstring=&amp;quot;&amp;quot;DSN=Excel Files;DBQ=L:\orders\Beneficial PORCEL.xls;DefaultDir=L:\orders;DriverId=1046;MaxBufferSize=2048&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 02100    open #1: &amp;quot;name=envdb.txt,replace&amp;quot;,display,output &lt;br /&gt;
 02200 Dump_Table: ! ***** Dump Table Layout&lt;br /&gt;
 02300    let OUTFD = 1&lt;br /&gt;
 02400    let ENV$(&amp;quot;status.database.LIST&amp;quot;, MAT DATABASES$)  !List of db&#039;s&lt;br /&gt;
 02500    for DATABASE=1 to UDIM(DATABASES$)  !For each connected database&lt;br /&gt;
 02600       let DATABASE$=DATABASES$(DATABASE)&lt;br /&gt;
 02700       let FNSHOW_DATABASE(DATABASE$, &amp;quot;status.database.&amp;quot;&amp;amp;DATABASE$)&lt;br /&gt;
 02800    next DATABASE&lt;br /&gt;
 02900    end &lt;br /&gt;
 03000 ! &lt;br /&gt;
 03100    def FNSHOW_DATABASE(DATABASE$*100, ST_PREFIX$*100)&lt;br /&gt;
 03200       print #OUTFD: DATABASE$&lt;br /&gt;
 03300       let OUT_PREFIX$=CHR$(9)&lt;br /&gt;
 03400       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;DSN=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.DSN&amp;quot;)&lt;br /&gt;
 03500       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;CONNECTSTRING=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.CONNECTSTRING&amp;quot;)&lt;br /&gt;
 03600       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Tables:&amp;quot;&lt;br /&gt;
 03700       let ST_PREFIX$=ST_PREFIX$&amp;amp;&amp;quot;.TABLES&amp;quot;&lt;br /&gt;
 03800       let ENV$(ST_PREFIX$&amp;amp;&amp;quot;.LIST&amp;quot;, MAT TABLES$)&lt;br /&gt;
 03900       for TABLE = 1 to UDIM(MAT TABLES$)&lt;br /&gt;
 04000          let TABLE$=TABLES$(TABLE)&lt;br /&gt;
 04100          let FNSHOW_TABLE(TABLE$,ST_PREFIX$&amp;amp;&amp;quot;.&amp;quot;&amp;amp;TABLE$,OUT_PREFIX$&amp;amp;CHR$(9))&lt;br /&gt;
 04200       next TABLE&lt;br /&gt;
 04300    fnend &lt;br /&gt;
 04400 ! &lt;br /&gt;
 04500    def FNSHOW_TABLE(TABLE$*100, ST_PREFIX$*100, OUT_PREFIX$)&lt;br /&gt;
 04600       print #OUTFD: OUT_PREFIX$&amp;amp;TABLE$&lt;br /&gt;
 04700       let OUT_PREFIX$=OUT_PREFIX$&amp;amp;CHR$(9)&lt;br /&gt;
 04800       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Table remarks=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.REMARKS&amp;quot;)&lt;br /&gt;
 04900       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Table type=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.TYPE&amp;quot;)&lt;br /&gt;
 05000       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Columns:&amp;quot;&lt;br /&gt;
 05100       let ST_PREFIX$=ST_PREFIX$&amp;amp;&amp;quot;.COLUMNS&amp;quot;&lt;br /&gt;
 05200       let ENV$(ST_PREFIX$&amp;amp;&amp;quot;.LIST&amp;quot;, MAT COLUMNS$)&lt;br /&gt;
 05300       for COLUMN = 1 to UDIM(MAT COLUMNS$)&lt;br /&gt;
 05400          let COLUMN$=COLUMNS$(COLUMN)&lt;br /&gt;
 05500          let FNSHOW_COLUMN(COLUMN$, ST_PREFIX$&amp;amp;&amp;quot;.&amp;quot;&amp;amp;COLUMN$,OUT_PREFIX$&amp;amp;CHR$(9))&lt;br /&gt;
 05600       next COLUMN&lt;br /&gt;
 05700    fnend &lt;br /&gt;
 05800 ! &lt;br /&gt;
 05900    def FNSHOW_COLUMN(COLUMN$*100, ST_PREFIX$*100, OUT_PREFIX$)&lt;br /&gt;
 06000       print #OUTFD: OUT_PREFIX$&amp;amp;COLUMN$&lt;br /&gt;
 06100       let OUT_PREFIX$=OUT_PREFIX$&amp;amp;CHR$(9)&lt;br /&gt;
 06200       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Column type=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.TYPE&amp;quot;)&lt;br /&gt;
 06300       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Column length=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.LENGTH&amp;quot;)&lt;br /&gt;
 06400       print #OUTFD: OUT_PREFIX$&amp;amp;&amp;quot;Column decimals=&amp;quot;&amp;amp;ENV$(ST_PREFIX$&amp;amp;&amp;quot;.DECIMALS&amp;quot;)&lt;br /&gt;
 06500    fnend&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
For more information about &#039;&#039;&#039;SQL&#039;&#039;&#039; or &#039;&#039;&#039;Structured Query Language&#039;&#039;&#039; see [[Wikipedia:SQL]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Terminology]]&lt;br /&gt;
[[Category:SQL]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Laura</name></author>
	</entry>
</feed>