ScreenIO Library: Difference between revisions
Gordon.dye (talk | contribs) mNo edit summary |
|||
(95 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
The '''ScreenIO Library''' is a Rapid Application Design tool that enables | The '''ScreenIO Library''' 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 "single screen" program can be created in minutes. | ||
Before we get any farther, if you're here for help with ScreenIO, here's a short list of common reference links: | Before we get any farther, if you're here for help with ScreenIO, here's a short list of common reference links: | ||
[[#ScreenIO Runtime Engine Library Functions|ScreenIO's fnFm Parameter List]]<br> | [[#ScreenIO Runtime Engine Library Functions|ScreenIO's fnFm Parameter List]]<br> | ||
[[#ScreenIO Events|Custom Function - Events]]<br> | [[#ScreenIO Screen Events|Custom Function - Events]]<br> | ||
[[#Writing Screen Helper Functions|Custom Function - Parameters]]<br> | [[#Writing Screen Helper Functions|Custom Function - Parameters]]<br> | ||
[[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]<br> | [[#Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)|Keyboard Reference]]<br> | ||
[[#Working with the ScreenIO Loading Icon|Animations]]<br> | [[#Working with the ScreenIO Loading Icon|Animations]]<br> | ||
[[#Useful ScreenIO Functions|Useful ScreenIO Functions]]<br> | |||
[[#ExitMode|ExitMode]]<br> | [[#ExitMode|ExitMode]]<br> | ||
[[ | |||
Using ScreenIO, the programs you create, called "screen functions", 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. | |||
They're called "Screen Functions" 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. | |||
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. | |||
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. | |||
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 "Screen Functions". Sage wrote our entire internal accounting system using "screen function" technology, in just a couple of weeks. | |||
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. | |||
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer. | |||
== Using ScreenIO Screens == | == Using ScreenIO Screens == | ||
Line 123: | Line 128: | ||
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. | 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. | ||
==== Calling your screen from an existing non-gui program ==== | |||
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. | |||
If you're using BR 4.2 or higher, thats all you need to do. If you'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'll also have to set env$("screenrows") and env$("screencols"). | |||
==== Returning Information from your screen ==== | ==== Returning Information from your screen ==== | ||
Line 156: | Line 166: | ||
The ScreenIO Functions listed above all accept the following parameters: | The ScreenIO Functions listed above all accept the following parameters: | ||
*Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter | *Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter. | ||
*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'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.<br><br>'''''Note:''' A Key should never be passed into a Listview screen'' | *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'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.<br><br>'''''Note:''' A Key should never be passed into a Listview screen'' | ||
Line 264: | Line 274: | ||
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. | 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. | ||
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. | 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. | ||
Line 281: | Line 291: | ||
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. | 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. | ||
=== The ScreenIO Animated Loading Icon === | === The ScreenIO Animated Loading Icon === | ||
Line 334: | Line 343: | ||
setting_PreviewListviews=1 | setting_PreviewListviews=1 | ||
setting_RealtimeFilters=0 | setting_RealtimeFilters=0 | ||
setting_load_filter=0 | |||
setting_functionsel_filter=1 | |||
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. | 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. | ||
Line 367: | Line 378: | ||
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. | 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. | ||
===Load Filter=== | |||
Controls weather there should be a filter box or a search box on the "Load Screen" dialog (2.3). | |||
===setting_functionsel_filter=== | |||
Controls weather there is a filter box or a search box on the the "Function Select" dialog screen. | |||
== Making ScreenIO Screens == | == Making ScreenIO Screens == | ||
Line 378: | Line 397: | ||
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. | 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. | ||
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. | ==== Saving Your Screen ==== | ||
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. | |||
To save your screen, it has to at least have a Screen Name. Once you've entered a Screen Name, you can save your screen using the Windows "File" dropdown menu (described below). Just click "File", then select "Save". | |||
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. | |||
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing "continue". If you do, save your screen as soon as possible. Then use FileIO's datacrawler to fix the problem in the screen that led to the crash. | |||
===== Screen Backups for Multi User Environments ===== | |||
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 "backup" folder in the screenio copy on your local copy and you'll find a screenname.sio file that is a backup of your screen the last time you saved it. | |||
By checking these backups into your Source Code Repository, you gain version history of your screenio screens. | |||
At any time, you can "import" one of these ".sio" files back into ScreenIO by using the "Import" option in the Windows Dropdown Menus. You'll want to check the name of the imported screen, and then save it using File -> Save, right away. | |||
==== Windows X ==== | |||
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR. | |||
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. | |||
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR. | If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR. | ||
Line 446: | Line 483: | ||
*Power Search | *Power Search | ||
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. | 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. | ||
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. | |||
*Code Explore | *Code Explore | ||
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. | 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. | ||
Line 456: | Line 496: | ||
*Orphaned Functions | *Orphaned Functions | ||
Displays a list of all functions in your functions folder that are no longer in use by any screens. | Displays a list of all functions in your functions folder that are no longer in use by any screens. | ||
===== Add Control ===== | ===== Add Control ===== | ||
The add control menu gives you keyboard access for adding any control you want to your screen. | The add control menu gives you keyboard access for adding any control you want to your screen. | ||
Line 587: | Line 628: | ||
====== Attributes ====== | ====== Attributes ====== | ||
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 "BORDER=S" in the Attributes setting for the window. | 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 "BORDER=S" in the Attributes setting for the window. | ||
If you're using color attributes, use N=, for example when [BackgroundColor] is set in a config attributes file, use N=[BackgroundColor]. | |||
====== Picture ====== | ====== Picture ====== | ||
Type the path and filename of a picture file, and it will be used as the background image for your Screen. | Type the path and filename of a picture file, and it will be used as the background image for your Screen. | ||
Line 635: | Line 679: | ||
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. | 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. | ||
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 "~ignore~". This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button. | 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 "~ignore~" (but no quotes). This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button. | ||
====== Combo Box ====== | ====== Combo Box ====== | ||
Line 645: | Line 689: | ||
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you'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. | One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you'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. | ||
For example: | |||
def fnPopulateApproval | |||
mat returndata$(3) | |||
let returndata$(1)="None" | |||
let returndata$(2)="Approve" | |||
let returndata$(3)="Hold" | |||
let fnPopulateApproval=1 | |||
fnend | |||
====== Listview ====== | ====== Listview ====== | ||
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter "Edit Listview Columns" 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. | This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter "Edit Listview Columns" 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. | ||
Line 787: | Line 842: | ||
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button. | The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button. | ||
===== Validation ===== | ===== Validation ===== | ||
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. | 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. | ||
===== Filter ===== | ===== Filter ===== | ||
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System. | The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System. | ||
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. | 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. | ||
Implement Read and Return keys in the Window Attribute Section because a 0 Read Key will default to a Relative Read. | |||
===== Conversion ===== | ===== Conversion ===== | ||
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. | 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. | ||
====== Special ScreenIO Date processing ====== | ====== Special ScreenIO Date processing ====== | ||
If you use DATE then it will convert the value from | 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. | ||
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. | 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. | ||
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 "five days from now", or +2w to say "14 days from now", or +3m or -1y, etc. | 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 "five days from now", or +2w to say "14 days from now", or +3m or -1y, etc. | ||
This also works in listviews to display the dates in any format you want, while still making sure they're numerically sortable. | |||
===== Picture File ===== | ===== Picture File ===== | ||
Line 869: | Line 930: | ||
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold. | Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold. | ||
You can write custom events to initialize your new record, unpack a record after reading it, validate a record before saving it, and open | 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's Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation. | ||
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen'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. | Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen'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. | ||
Line 878: | Line 939: | ||
==== ScreenIO Events ==== | ==== ScreenIO Screen Events ==== | ||
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event. | The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event. | ||
Line 934: | Line 995: | ||
====== Listview Prepopulate ====== | ====== Listview Prepopulate ====== | ||
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. | 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. | ||
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method. | |||
====== Listview Postpopulate ====== | ====== Listview Postpopulate ====== | ||
Line 942: | Line 1,005: | ||
===== Default Event Functions ===== | ===== Default Event Functions ===== | ||
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called "defaults" under your "function" folder, (so "function\defaults") and placing the event functions you want in there with the appropriate name. | ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called "defaults" under your "function" folder, (so "function\defaults") and placing the event functions you want in there with the appropriate name. | ||
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 "function\defaults" folder and rename it to the correct name for the event type that you want it to be. | |||
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. | 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. | ||
Line 947: | Line 1,012: | ||
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. | 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. | ||
Every Screen Level event function is supported | Every Screen Level event function is supported: | ||
*enter.brs | |||
*init.brs | |||
*read.brs | |||
*load.brs | |||
*write.brs | |||
*wait.brs | |||
*locked.brs | |||
*merge.brs* | |||
*mainloop.brs | |||
*nokey.brs* | |||
*prelist.brs | |||
*postlist.brs | |||
*exit.brs | |||
<nowiki> * </nowiki>Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run ''In addition to'' any function selected in the screen. | |||
===== Control Specific Events ===== | ===== Control Specific Events ===== | ||
Line 960: | Line 1,040: | ||
See Example [[#Validate_Field_Function|Validate Field Function]]. | See Example [[#Validate_Field_Function|Validate Field Function]]. | ||
====== Filter Event ====== | ====== Filter Event ====== | ||
The Filter function is the most versatile | 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. | ||
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. | 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. | ||
See | If your filter function returns a valid color code, (ex: "/#0000FF:000000" a hex code or "[HILITECOLOR]" an attribute substitution statement from your brconfig.sys), then the row is colored that color. | ||
If your filter function returns the word "STOP", then screenio stops reading the data file and also doesn't include the record in the list. You can use this function to make listview functions run faster. | |||
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've moved past the last record that you want to display, return "STOP". | |||
For an example of a listview filter function, See [[#Listview_Filter_Function|Listview Filter Function]]. | |||
====== fnInit_ and fnFinal_ ====== | |||
''Added in ScreenIO v91'' | |||
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. | |||
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]]). | |||
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'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. | |||
When you create a new [[#Filter_Event|Filter Function]] in the newest versions of ScreenIO, they'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. | |||
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. | |||
See [[#Listview_Filter_Function|Example]]. | |||
====== Conversion Function ====== | ====== Conversion Function ====== | ||
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 "CNVRT$" function. | 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 "CNVRT$" function. | ||
Line 1,023: | Line 1,125: | ||
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command. | For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command. | ||
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. | 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. | ||
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: | 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: | ||
Line 1,114: | Line 1,216: | ||
*'''Key$''' - This is the Key that we called the screen with | *'''Key$''' - This is the Key that we called the screen with | ||
*'''[[#ExitMode|ExitMode]]''' - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit. | *'''[[#ExitMode|ExitMode]]''' - Set [[#ExitMode|ExitMode]] to non-zero to cause your screen to exit. | ||
*'''RepopulateListviews''' - Set this value to True in your function to cause ScreenIO to redraw the | *'''RepopulateListviews''' - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code. | ||
*'''RedrawListviews''' - 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. | |||
*'''RedrawFrames''' - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen. | |||
*'''RedrawScreens''' - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen. | |||
*'''RepopulateCombo''' - Set this value to True in your function to cause ScreenIO to rerun all your "RepopulateCombo" functions and repopulate all the combo boxes on your screen. | |||
*'''Prefix$''' - Prefix for your FileIO Data File | *'''Prefix$''' - Prefix for your FileIO Data File | ||
*'''Currentkey$''' - Currently selected key from your data file | *'''Currentkey$''' - Currently selected key from your data file | ||
*'''rec(datafile)''' - | *'''rec(datafile)''' - if you need to know the current record in the primary data file you can use the BR system function REC to discover it. | ||
*'''mat SelectedKeys$''' - If you have a listview with multiselect enabled, use this array to access the keys of all selected records | *'''[[#Working_with_Listviews|mat SelectedKeys$]]''' - If you have a listview with multiselect enabled, use this array to access the keys of all selected records. | ||
*'''mat SelectedRecords''' - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. | *'''[[#Working_with_Listviews|mat SelectedRecords]]''' - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records. | ||
*'''[[#Working_with_Listviews|mat VisibleKeys$]]''' - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+) | |||
*'''[[#Working_with_Listviews|mat VisibleRecords]]''' - All the records that are currently visible in the listview (v91,Requires BR 4.3+) | |||
*'''mat Save_F$''' - 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. | *'''mat Save_F$''' - 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. | ||
*'''mat Save_F''' - 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. | *'''mat Save_F''' - 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. | ||
Line 1,134: | Line 1,242: | ||
*'''Currentfield''' - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around. | *'''Currentfield''' - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around. | ||
*'''Currentfield$''' - 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. | *'''Currentfield$''' - 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. | ||
*'''DisplayOnly''' - 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. | |||
*'''Selecting''' - 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. | |||
*'''''Only Available in Validate and Conversion Functions''''' - 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: | *'''''Only Available in Validate and Conversion Functions''''' - 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: | ||
**'''Fieldtext$''' - This is the text in the field being validated/converted. | **'''Fieldtext$''' - This is the text in the field being validated/converted. | ||
Line 1,150: | Line 1,260: | ||
in a comment somewhere in your program and the specified custom helper function will be included. The "{}"s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO. | in a comment somewhere in your program and the specified custom helper function will be included. The "{}"s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO. | ||
===== Prewritten Functions ===== | |||
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'll mention a couple of them here. | |||
*'''deletelistviewrecord''' - Displays a confirmation dialog, and then deletes the currently selected record in a listview. | |||
*'''deleterecord''' - Displays a confirmation dialog, and then deletes the current record in an add/edit screen. | |||
*'''enforcerecord1''' - 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. | |||
*'''enterselectionlistview, filterselection, and toggleselection''' - These three functions work together to make listview screens where the user can toggle on and off a selection of them. | |||
*'''listviewcombo[...]''' - 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. | |||
*'''pause''' - 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. | |||
*'''printlistview''' - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer. It requires George Tisdale'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]]. | |||
*'''exportlistviewcsv''' - 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). | |||
*'''exportcurrentfilecsv''' - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there's a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. '''''Note: '''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 "X" fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.'' | |||
====== ====== | |||
===== Examples ===== | ===== Examples ===== | ||
Line 1,189: | Line 1,314: | ||
def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$) | def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$) | ||
mat Employee$=("") : mat Employee=(0) | |||
read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore | |||
let s$(sio_EmployeeName)=Employee$(em_name) | |||
if CurrentEmployee$="" then | if CurrentEmployee$="" then | ||
library "timelib" : fnCurrentEmployee$ | library "timelib" : fnCurrentEmployee$ | ||
Line 1,210: | Line 1,339: | ||
if sio_taskstatus then let s$(sio_taskstatus)="Z" ! Cancelled | if sio_taskstatus then let s$(sio_taskstatus)="Z" ! Cancelled | ||
end if | end if | ||
fnend | |||
dim Employee$(1)*1023,Employee(1),Employee | |||
def fnInit_FilterTasks | |||
let Employee=fnOpen("employee",mat Employee$,mat Employee,mat Form$,1) | |||
fnend | |||
def fnFinal_FilterTasks | |||
Close #Employee: | |||
fnend | fnend | ||
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]]). | |||
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're cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa. | |||
When you create a new Filter Function in the newest versions of ScreenIO, they'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. | |||
These are the preferred method for populating listviews. They'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. | |||
fnInit_ and fnFilter_ were added in ScreenIO v91. | |||
====== Click Event Function ====== | ====== Click Event Function ====== | ||
Line 1,336: | Line 1,484: | ||
===== ScreenIO Built In functions ===== | ===== ScreenIO Built In functions ===== | ||
ScreenIO has | ScreenIO has several [[#Functions_to_use_in_your_ScreenIO_Functions|built in functions]] for use in your events. | ||
===== Mat S$ ===== | ===== Mat S$ ===== | ||
Line 1,377: | Line 1,520: | ||
*ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic. | *ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic. | ||
*ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they'd like to Save or just Quit, and behave accordingly. If the user hasn't changed anything, it will just quit. | *ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they'd like to Save or just Quit, and behave accordingly. If the user hasn't changed anything, it will just quit. | ||
*ExitMode=Reload... will not save but will reload the screen. | |||
*ExitMode=AutoReload | |||
To set ExitMode in one of your functions, simply assign it a value from the list above. | To set ExitMode in one of your functions, simply assign it a value from the list above. | ||
Line 1,388: | Line 1,533: | ||
let Quitother=4 | let Quitother=4 | ||
let Asksaveandquit=5 | let Asksaveandquit=5 | ||
let Reload=6 | |||
let AutoReload=7 | |||
=== Working with | ===== Working with Listviews ===== | ||
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. | |||
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. | 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. | ||
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'll contain every row if the listview hasn'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. | |||
=== Working with the ScreenIO Loading Icon === | |||
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. | |||
You don'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. | You don'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. | ||
However, if you like, you can use these animations in your own programs, by calling the [[#Animations|ScreenIO Animation Functions]]. | |||
==== Changing the Loading Icon ==== | ==== Changing the Loading Icon ==== | ||
Line 1,426: | Line 1,582: | ||
If you've made a nice clock, and you'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. | If you've made a nice clock, and you'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. | ||
=== Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) === | === Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more) === | ||
Line 1,464: | Line 1,619: | ||
Ctrl-S .. Toggle Selection for current control | Ctrl-S .. Toggle Selection for current control | ||
Ctrl-T .. Select All Textboxes | Ctrl-T .. Select All Textboxes | ||
Ctrl-I .. Select Inverse | |||
F7 ...... Select All Controls | |||
Esc ..... Unselect all or exit the current control | Esc ..... Unselect all or exit the current control | ||
F6 ...... Draw or Redraw the Movement Grid | F6 ...... Draw or Redraw the Movement Grid | ||
Line 1,484: | Line 1,641: | ||
''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]].'' | ''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]].'' | ||
== | === Support for New Fileio Dates === | ||
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. | |||
There is now a new Control Attribute called "Disk Date Format" 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. | |||
[[File:Dates1.png]] | |||
This works on listviews too, so you can now specify these two fields, to make dates show as, for example "January 24, 2018", even if they're saved on disk as "MMDDCCYY". Or, like in the following example, as "MM/DD/CCYY" even though they're saved on disk as "MDY". Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is. | |||
[[File:Dates2.png]] | |||
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. | |||
ScreenIO also has a new INI setting you can control: | |||
CODE: SELECT ALL | |||
setting_DateFormatDisplay$="m/d/cy" | |||
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. | |||
== Useful ScreenIO Functions == | |||
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's Loading Animations, for example, are available for use in any of your BR programs. | |||
== | === Functions to use in your ScreenIO Functions === | ||
These functions are designed to be run from one of your helper functions, to interrogate the current screen and get additional information. | |||
*Add your Feature | ==== fnFunctionBase ==== | ||
*Requests Here | |||
fnFunctionBase returns the Function Base of the current screen. Use it for interpreting which control was clicked on, in your Mainloop Event. | |||
This function is designed to run from within your screen, from one of your custom functions. | |||
Example: | |||
if fkey-fnFunctionBase=ctl_Name then | |||
! Name field was clicked on | |||
end if | |||
==== fnIsOutputSpec and fnIsInputSpec ==== | |||
<boolean>=fnIsOutputSpec(FieldType$) | |||
<boolean>=fnIsInputSpec(FieldType$) | |||
These functions are used to tell if ScreenIO would treat the given control as an Input Spec or an output Spec | |||
They are designed to run from within your screen, from one of your custom functions. | |||
Example: | |||
if fnIsOutputSpec(FieldType$(ControlIndex)) then | |||
! the current control this Validation or Click Event function is running under is a control that ScreenIO would treat as Output Only | |||
end if | |||
*Control Index always returns the current control that a Validate or Click event function is running under. | |||
==== fnGetUniqueName$ ==== | |||
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. | |||
Example: | |||
let msgbox("The current control has a unique name of "&fnGetUniqueName$(mat ControlName$,ControlIndex) | |||
*Control Index always returns the current control that a Validate or Click event function is running under. | |||
==== fnFindSubscript ==== | |||
fnFindSubscript(MAT Subscripts$,Prefix$,String$*40) | |||
Used to find the Subscript of the control you're searching for, when you have that controls name as a String. It searches the Subscripts array. This does the inverse of fnGetUniqueName$ above. | |||
Example: | |||
let index=fnFindSubscript(mat Subscripts$,"ctl_",TheNameOfTheControl$) | |||
=== Functions for use in your own programs === | |||
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. | |||
==== Animations ==== | |||
let fnPrepareAnimation | |||
let fnAnimate(;Text$*60) | |||
let fnCloseAnimation | |||
The [[#Working with the ScreenIO Loading Icon|ScreenIO Loading Animations]] can be used in your own programs. | |||
Example: | |||
let fnPrepareAnimation | |||
for SomeReallyLongTask=1 to 1000 | |||
let fnAnimate(str$(int(100*SomeReallyLongTask/1000))&" percent complete!") | |||
! Do some long slow thing | |||
next SomeReallyLongTask | |||
let fnCloseAnimation | |||
==== fnDays ==== | |||
fnDays(UserEnteredDate$*255;DateSpec$*255) | |||
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. | |||
==== fnBr42 and fnBr43 ==== | |||
fnBr42 | |||
fnBr43 | |||
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. | |||
==== fnListSpec$ ==== | |||
fnListSpec$*255(SPECIN$*255) | |||
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. | |||
=== Functions to interact with the ScreenIO Designer === | |||
These next few functions can be used to run and interface with the screenio designer directly. | |||
==== fnDesignScreen ==== | |||
fnDesignScreen(;ScreenName$) | |||
This function runs the ScreenIO Designer. If the optional Screen name is given, then that screen is loaded for editing. | |||
==== fnSelectEvent$ ==== | |||
fnSelectEvent$*255(Current$*255;&ReturnFkey) | |||
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. | |||
==Update Process== | |||
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. | |||
If you do not get this message when updating, don'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. | |||
Your ScreenIO Helper Libraries have been moved into a new folder called 'screenio\'. 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 'include screenio\screenio.sys' to your brconfig.sys file. | |||
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's names conflict with your data files. | |||
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com. | |||
== Future Changes == | |||
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you'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. | |||
=== New Future Change Requests === | |||
All currently requested features have been implemented. If you have a feature in mind you'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'll remove it from the list that you make here. | |||
*Add your Feature | |||
*Requests Here | |||
=== Completed Future Change Requests === | === Completed Future Change Requests === | ||
The following list of change requests | The following list shows some of the change requests that have been completed. | ||
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 "Recent Changes". | |||
*Filter Functions now include the ability to specify an "Init" and a "Final" 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). | |||
*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). | |||
*Added support for FileIO'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). | |||
*Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+) | |||
*Fixed the Generate Screen function to use Filter Boxes (v2.47). | |||
*Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46). | |||
*Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45). | |||
*Added feature where putting "N" in for the CNVRT spec property forces them to enter only valid numbers (v2.42). | |||
*Added ability to put in just "N" instead of having to put the whole spec "N 10" for the CNVRT spec property (v2.42). | |||
*Fixed a bug in the Orphaned Functions list (v2.4) | |||
Spring Conference 2017 Release, v2.3: | |||
*Added filter boxes for Screen Selection and Function Select | |||
*Added options to ini file to enable or disable them | |||
setting_Load_Filter | |||
setting_FunctionSel_Filter | |||
*Added Version Number to Comments in Program | |||
*Made fnDesignScreen callable as a function | |||
*Made File Layout List redraw every time so it reflects recent Layout Changes | |||
*Fixed a bug in the "Launch Screen in New Window" code | |||
*Added Screen Version field | |||
*Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts | |||
*Fixed a compatibility issue for using Substitute to rearrange your folder structure | |||
*Added a better message for Out Of Date Helper Libraries | |||
*Began Tracking ScreenIO Version Carefully | |||
Previous Changes: | |||
*Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen. | *Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen. |
Latest revision as of 21:15, 31 July 2022
The ScreenIO Library 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 "single screen" program can be created in minutes.
Before we get any farther, if you're here for help with ScreenIO, here's a short list of common reference links:
ScreenIO's fnFm Parameter List
Custom Function - Events
Custom Function - Parameters
Keyboard Reference
Animations
Useful ScreenIO Functions
ExitMode
Using ScreenIO, the programs you create, called "screen functions", 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.
They're called "Screen Functions" 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.
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.
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.
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 "Screen Functions". Sage wrote our entire internal accounting system using "screen function" technology, in just a couple of weeks.
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.
The ScreenIO Library is a third party developer tool created and marketed by Sage AX to the BR programmer.
Using ScreenIO Screens
This section of the documentation deals with all of the ways to make use of your screens created with the ScreenIO system.
Screen Functions
What is a Screen Function?
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.
Screens are Modular and Reusable. That means you can create a screen for selecting a customer from a listview on the screen. This "Listview Screen" can also have buttons that chain to other screens, such as an Add/Edit Screen.
Now you have a complete FM program in two screens, for maintaining the customer file. But wait, what if you need a "Customer Selection" listview in your other programs? No problem, the same "Screen Function" program that was run before as your Customer FM, can also be run as a library function, as your Customer Selection screen.
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.
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.
By Combining four screens together, we can even write File Maintenance programs that work on two data files simultaneously, with a parent/child relationship!
How does it work?
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 "compile" 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.
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:
LIBRARY "screenio" : fnfm$ let Result$=fnfm$("scrnname")
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.
What can a Screen Function Do?
A Screen Function can do many things. A Screen Function right now generally fits into three categories:
1. A Listview Screen Function 2. An Add/Edit Screen Function 3. A Menu/Simple Screen Function
Listview Screen Function
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.
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'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.
Add/Edit Screen Function
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'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.
An Add/Edit Screen Function is the easiest way to create any sort of user interface asking for specific data from a customer.
A Menu/Simple Screen Function
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.
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.
Implementation Guide
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.
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't worry about it. If you buy a screen from Sage AX, we'll tell you which options apply to your screen.
Installing your new screen
When you order a screen, Sage will send you the following files:
data\screenio.dat - Screen Header Data file containing your new screen and all your old screens data\screenio.key - Screen Header Key file data\screenfld.dat - Screen Fields Data file containing all the fields for your screens data\screenfld.key - Screen Fields Key file data\screenfld.ky2 - Screen Fields Key file screenio.br - Free ScreenIO Runtime Library required to run your screens screenio\scrnname.br - Screen helper library (compiled in a br program) screenio\scrnname.brs - Screen helper library (BR Source File, included for your convenience only.)
"scrnname" is replaced by the name of your new screen.
To begin using your new screens, simply copy the files into the main folder of your BR programs.
Running your new screen
You can now run your new screen by simply typing:
LOAD scrnname RUN
Calling your screen from your existing programs
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.
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.
01000 LIBRARY "screenio" : fnfm 01200 let fnfm("scrnname")
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.
Calling your screen from an existing non-gui program
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.
If you're using BR 4.2 or higher, thats all you need to do. If you'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'll also have to set env$("screenrows") and env$("screencols").
Returning Information from your screen
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.
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.
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.
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're done.
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.
Advanced Screen Implementation
ScreenIO Runtime Engine Library Functions
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:
- fnfm("scrnname"; 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't cancel, or 0 if they did.
- fnfm$("scrnname"; 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 "str$()" of the numeric return value of the screen. Use "val()" to turn it back into a number if you need.
- fnDisplayScreen("scrnname"; 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.)
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$="blah" : ParentKey$="blahblah". Row, Col, Key$, and ParentKey$ Are optional. You can also specify Record=, Selecting=, DisplayOnly=, and Path$=.
The simplest (and most common) form is just to say [SCRNNAME]
ScreenIO Runtime Engine Library Function Parameters
The ScreenIO Functions listed above all accept the following parameters:
- Scrnname$ - This is the name of the screen you are trying to call. This is the only required parameter.
- 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'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.
Note: A Key should never be passed into a Listview screen
- 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.
- 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).
- 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.
- 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 "str$()" value of the window number of the newly opened Screen Function - use "val()" to get the actual Window Number as a numeric value.
- 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're calling a screen that doesn'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're returning to. If you're implementing a screen that Sage AX made for you, we will have already set this for you.
Example: If you're in a listview screen and its calling an add/edit screen, this parameter is used on the call to the add/edit screen but it applies to the listview screen.
- RecordVal - If you are editing a record in an Add/Edit Screen By Record instead of by Key, specify the Record here, and leave "Key$" blank.
- 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're implementing a screen from Sage AX, we will tell you if there is any custom data you need to pass in.
- 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're passing in. Use this for an Add/Edit screen when you don't want ScreenIO to read or write the record on disk.
- 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.
- 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.
- 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.
- Selecting - This is a flag you can use to signal to your screens when you're running them as to the intentions of your users. You can use it to define different "modes" 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.
How does it work Internally
Program Flow
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.
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 "ExitMode" is triggered, either from one of the events, or by pressing the ESC key to trigger an ExitMode of Cancel (by default), or the ENTER key to trigger an ExitMode of Select (by Default).
Once a Screen Function Event has been triggered that sets ExitMode to one of the various valid exit modes, the screen is exited, and depending on 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.
Philosophy
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.
ScreenIO was designed to eliminate the BR headache of working with 2D object-style controls in the non-object oriented world of BR programming.
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'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.
Instead, ScreenIO's focus is on remaining as simple as possible, while still allowing the flexibility to accomplish 90% of the business programming purposes. It can'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.
Modular
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.
Event Driven
Because ScreenIO is Event Driven, it is easy to call any of your existing business logic code from one of our screens.
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.
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.
Screen Events
- Enter Event: This event is triggered when your screen is first displayed.
- 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.
- 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.
- Write Event: This event is triggered when the user selects the "Save" 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.
- 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's in your screenio screens.
- 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.
- 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.
- Exit Event: This event is triggered last, when the screen is being closed.
Individual Control Events
Each of the controls on your screen has its own event, which get triggered in various ways depending on the control.
- 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.
- Listviews
- Validation - In a data Control, the data Control'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).
- TextBoxes
- CheckBoxes
- SearchBoxes
- Radio Buttons
- Filter Boxes
- Combo Boxes
- Click Events - Non-Data Controls have a "Click" event. This event is triggered whenever the user clicks on the control.
- Buttons
- Pictures
- Captions
Purpose of Events
By overriding various events with custom code, we can make your screen functions behave any way you want them to.
Screens with two data files
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.
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.
Example
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.
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).
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.
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 "DisplayOnly" in the second screens "Enter Event", 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.
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.
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.
The ScreenIO Animated Loading Icon
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.
You don'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.
Changing the Loading Icon
See Working with the ScreenIO Loading Icon for more information.
Save Money with Screen Functions
Lower Development Costs
A "Screen Function", 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.
Because the screens are contained in Data files, they are easy to modify and easy to maintain.
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.
Lower Maintenance Costs
The ScreenIO Runtime Library required to run your screens is free.
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.
You don't need any special editor to edit the custom code that'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.
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.
Estimated Price for your Screen Project
Please contact Sage AX (gabriel.bakker@gmail.com) with your project details to recieve a free price quote.
Visit http://www.sageax.com/products/screenio-library/ for more details.
Screenio.ini
ScreenIO can be configured by creating a file named ScreenIO.ini and placing it either in the root folder or in the screenio folder.
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.
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.
Setting_EnableLogging=0 setting_FileIOPath$="fileio" setting_ScreenIOPath$="screenio" setting_ClockPath$="clocks\clock" setting_ImagePath$="images" setting_ScreenFolder$="screenio" setting_ClickToMove=1 setting_PreviewListviews=1 setting_RealtimeFilters=0 setting_load_filter=0 setting_functionsel_filter=1
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.
EnableLogging
This enables automatic logging via fileio's log function. See the FileIO documentation for more details.
FileIOPath$
This specifies the path to your copy of FileIO.
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.
ScreenIOPath$
This is the path and filename of your copy of screenio. See note above regarding nonstandard paths.
ClockPath$
This is the path to your clock files, used for the screenio loading animation.
ImagePath$
This is the path to your screenio images folder, used for drawing the movement grid and the search icons.
ScreenFolder$
This is the folder to store the compiled screen helper libraries.
ClickToMove
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 "Tools".
PreviewListviews
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.
RealtimeFilters
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'll make the designer crash, potentially causing you to loose the latest changes to the screen you're working on.
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.
Load Filter
Controls weather there should be a filter box or a search box on the "Load Screen" dialog (2.3).
setting_functionsel_filter
Controls weather there is a filter box or a search box on the the "Function Select" dialog screen.
Making ScreenIO Screens
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.
The ScreenIO Designer (Overview and Reference)
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.
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.
Saving Your Screen
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.
To save your screen, it has to at least have a Screen Name. Once you've entered a Screen Name, you can save your screen using the Windows "File" dropdown menu (described below). Just click "File", then select "Save".
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.
If you encounter an error in ScreenIO while designing your screen, you can often times get past the error by typing "continue". If you do, save your screen as soon as possible. Then use FileIO's datacrawler to fix the problem in the screen that led to the crash.
Screen Backups for Multi User Environments
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 "backup" folder in the screenio copy on your local copy and you'll find a screenname.sio file that is a backup of your screen the last time you saved it.
By checking these backups into your Source Code Repository, you gain version history of your screenio screens.
At any time, you can "import" one of these ".sio" files back into ScreenIO by using the "Import" option in the Windows Dropdown Menus. You'll want to check the name of the imported screen, and then save it using File -> Save, right away.
Windows X
Clicking on the Windows X from the ScreenIO Designer will close the ScreenIO Designer and exit BR.
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.
If there is no calling program, then clicking on the Windows X when running a ScreenIO screen will close the program and exit BR.
ScreenIO Windows Menu
File
File Options
- New
Create a new screen.
- Load
Load a previously saved screen.
- Save and Compile
Save and Compile your screen.
- Compile
Compile your screen only. Use this if you've changed some code but you haven't changed the screen itself.
- Save and Test
Save and Compile and Test your screen with one click.
- Export Screen
Export your screen to a ScreenIO File (*.sio) for transferring it between different ScreenIO implementations.
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.
- Import Screen
Import a screen from a ScreenIO File (*.sio).
- Purge ScreenFlds File
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.
- Recompile All Screens
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.
- FileIO
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.
- New Window
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.
- BR Console
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.
- Explore Local Folder
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.
- Quit
Exits ScreenIO and closes BR.
Options
Performance Options
- Click to Move
Default: On
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).
The Click to Move dots are particularly slow when you are modifying large 2D controls such as ListViews.
- Preview Listviews
Default: On
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.
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.
Previewing the listviews can be very slow for large data files. If you wish to increase performance, turn the "Preview Listviews" setting off.
- Real Time Filters
Default: Off
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.
Depending on the resources of your computer, this setting can have a serious impact on performance.
If the Preview Listviews setting is turned off, then the Real Time Filters setting has no effect.
Tools
Developer tools to help you with development in ScreenIO.
- Power Search
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.
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.
- Code Explore
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.
- Generate Screen
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.
- Generate Code
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't include your custom function processes.
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're writing.
- Orphaned Functions
Displays a list of all functions in your functions folder that are no longer in use by any screens.
Add Control
The add control menu gives you keyboard access for adding any control you want to your screen.
- Add Field
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 "Enter".
- Add Exit Buttons
This automatically adds Exit buttons to your screen. If its a listview screen, then it adds "Select" and "Cancel" buttons. If its an Add/Edit screen, then it gives you "Save" and "Cancel" buttons. These buttons are added to the bottom right corner of your screen, lining up with your rightmost controls.
- Add Add/Edit Buttons
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.
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.
- Add Textbox
Adds a Textbox. This is the same as clicking the button in your Toolbox.
- Add Caption
Adds a Caption. This is the same as clicking the button in your Toolbox.
- Add Checkbox
Adds a Checkbox or a Radio Button. This is the same as clicking the button in your Toolbox.
- Add Combo Box
Adds an empty Combo Box to your screen. You'll need to specify a combo "Populate" 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.
- Add Listview
Adds a Listview to your screen. This is the same as clicking the button in your Toolbox.
- Add Searchbox
Adds a SearchBox to your screen. This is the same as clicking the button in your Toolbox.
- Add Filterbox (4.3+)
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.
- Add Button
Adds a Button. This is the same as clicking the button in your Toolbox.
- Add Picture
Adds a Picture. This is the same as clicking the button in your Toolbox.
- Add Frame
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.
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.
You can always resize your screen to make it bigger temporarily, so you have space to work with when putting controls on your frame.
- Add Screen
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.
If they'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.
- Skip A Space
Skips a space for the automatic placement of controls. This is the same as clicking the button in your Toolbox.
Screen
Screen Options
- Adjust Screen Size
Automatically resizes your screen to just large enough to fit all your controls on it.
- Move Controls
This puts ScreenIO into Control Movement Mode
- Draw Movement Grid
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.
- Visit Checklist
This puts the curser in the Debug listview. You can do the same thing by clicking on the Debug Listview.
- Set FG Color
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.
- Set BG Color
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.
- Select File Layout
This brings up the file selection dialog. This is the same as clicking on the button in the Window Attributes panel.
- Set Events
This menu option does the same thing that clicking on the "Set Events" button (under Window Attributes) does: It opens a window where you can specify your Screen level Event Handler Custom Screen Functions.
- Set Tab Order
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 "Set Tab Order" button in the Window Attributes corner of the ScreenIO Designer.
- Configure Debug
This option allows you to specify any special instructions to use when testing the screen via the Test Screen menu option below.
- Configure Additional Info
This opens a window to configure additional screen level options that didn't fit on the main ScreenIO screen Attributes window.
- Test Screen
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't have to worry about the test of the screen screwing up whats going on in your editor.
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.
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.
Help
Help Menu
- Documentation
This menu option links to this wiki document.
- About
Opens the ScreenIO About screen.
ScreenIO Designer Modes
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.
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:
let Inputattributesmode=1 let Inputfieldlistmode=2 let Inputeditormode=3 let Inputeditormovemode=4 let Inputdebugmode=5 let Quitmode=6 let Selectcolormode=7 let Selectfilelaymode=8 let Inputlistviewmode=9 let Selecteventsmode=10 let Settabordermode=11 let Configuredebugmode=12
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're in a different mode and you click on the Window Attributes, then the mode is changed to Window Attributes mode. Input FieldsList Mode is when the cursor is in the fields listview, and you're selecting fields to add to the screen. Input Editor Mode is when the cursor is in the attributes for a single field. Input Editor Move Mode is when the cursor is in the mode where you move controls, the mode with the blue dots. Input Debug Mode is when the Todo List debug at the bottom of the screen is active. Quit Mode is used to tell the designer to exit. Select Color Mode is the current mode whenever you're selecting a color for something. Select FileLay Mode is used to select the file layout for your screen. Input Listview Mode is the mode for entering the information for listview columns. Select Events mode is the mode you're in when you're selecting screen level events. Set Tab Order Mode is the mode for setting the tab order. Configure Debug Mode is the mode for configuring the debug window.
You can generally tell what mode you're in because that part of the screen will light up yellow.
Toolbar
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.
Window Attributes
The Window Attributes window contains information about all Screen level Attributes.
Window Name
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->Load menu.
Caption
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
Rows
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.
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.
Cols
The number of Columns your window takes up. See Rows (above) for more information.
Attributes
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 "BORDER=S" in the Attributes setting for the window.
If you're using color attributes, use N=, for example when [BackgroundColor] is set in a config attributes file, use N=[BackgroundColor].
Picture
Type the path and filename of a picture file, and it will be used as the background image for your Screen.
Read Key
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.
Return Key
Specify the key to use when calculating the return value. The default is the first key specified in the layout.
Input Attr
Specify the Input Attr spec to use in the main Rinput Fields statement. This controls the appearance of the currently active field.
Wait Time
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.
FG Color
This is the default Foreground Color when adding new controls to the screen.
BG Color
This is the background color for the screen.
File Layout
Click this button to select the file layout that your screen applies to.
Set Form Events
This button is a shortcut to the Windows Menu: Screen->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.
Set Tab Order
This button is a shortcut to the Windows Menu: Screen->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.
Field List
This listview shows all the fields in the currently selected File Layout.
Because of a limitation in BR, only one child window can be active at any given time. You can tell if you are in "Input Fields List Mode" because the background for the Listview will turn Yellow. When you are in "Input Fields List Mode," 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.
Toolbox
The toolbox contains buttons for adding each of the different control types supported by ScreenIO.
Field
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.
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.
TextBox
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.
MultiLine Textbox
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.
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.
Caption
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
CheckBox
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.
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.
Radio Button
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.
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.
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 "~ignore~" (but no quotes). This will instruct ScreenIO to ignore the falsevalue, saving the truevalue from the currently selected radio button.
Combo Box
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.
Then you'll need to write a Combo Box Populate Function so that ScreenIO can populate your new combo box.
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're done. ScreenIO will run your populate function and everything you return will be placed inside the combo box.
One thing to be aware of, is your combo box populate function doubles as a traditional Validate function, so you'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.
For example:
def fnPopulateApproval mat returndata$(3) let returndata$(1)="None" let returndata$(2)="Approve" let returndata$(3)="Hold" let fnPopulateApproval=1 fnend
Listview
This button adds an empty listview to your new screen. This Listview can then be configured and modified. If you enter "Edit Listview Columns" 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.
Search Box
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.
Filter Box (4.3+)
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.
By default, a case insensitive fullrow search is performed, but you can change that in the filter boxes attributes window.
Button
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.
Picture
This button adds a Picture object to your new screen. Pictures, like buttons, also have a click event.
Frame
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.
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'll collect all the controls on top of each other along the leading edge of the frame.
Screen
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.
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's no listveiw on the child screen) and the action for the item they clicked on will be carried out in a natural fashion.
Skip a Space
This instructs ScreenIO to skip a row for the automatic placement of Screen Controls.
Editor
The Editor Window contains your new screen.
From the Editor Window you can move your Screen Controls around, and also edit each of their attributes and event functions.
Debug
The Debug window lists potential warnings and errors discovered by our Screen validation routine.
Messages in Blue are Warnings. They point to things that our ScreenIO Validation routine believes don't really make sense, even though they aren't really going to cause an error.
Messages in Red are Errors. If those problems are not corrected, your screen will not function properly.
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.
Using the ScreenIO Designer
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.
Create a New Screen
The first thing that every screen needs is a Screen Name.
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 "Window Name cannot be blank." (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.)
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->Load menu.
Enter a name for your new screen.
The next step is to Select the File Layout for your screen.
One of the nicest features of ScreenIO enabling truly Rapid Application Development, is ScreenIO's ability to automatically modify data files that have been defined within the FileIO Library system.
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 Librarys page on this wiki.
Click the button to the right of the text "File Layout:". Select the file layout for the file you plan to interact with using this screen.
Add Fields to your new Screen
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 "Add Field" button (or pressing "Enter" from the Field List listview).
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.
If you'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'd like it, press Enter twice, to go to "Edit Listview Columns Mode". Click the "Delete Column" 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.
Position the fields on your new Screen
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.
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.
This piece of magic is accomplished via the Caption Field poperty.
Keyboard Control Movement
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 Keyboard Reference.
Click to Move Control Movement
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.
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.
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.
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.
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.
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.
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.
Control Attributes Window
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.
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.
Here is a list of all the available Control Attributes and what they do:
Control Name
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.
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).
Field
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).
Caption
This is the caption for your Caption Fields, Check Boxes, and Buttons. This is the Tool Tip Text for your Buttons (not implemented yet).
Caption Field
This is the Control Name of the field that is tied to this field for movement purposes.
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.
Spec Width
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 "Space" or "BackSpace" when you are in Movement Mode and the control is selected. The Spec Width specifies how wide the data in the control can be.
Sort Column
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.
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.
For example, if you want it to sort in Descending Order on the Second Column, then specify a Sort Column of -2.
Multiselect
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.
Truth Value
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.
Everybody uses something slightly different in their data files to represent True and False. Some people use "Y" or "N". Some people use "T" and "F". 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.
Falsehood Value
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.
Everybody uses something slightly different in their data files to represent True and False. Some people use "Y" or "N". Some people use "T" and "F". 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.
~Ignore~ (Radio Buttons)
If you are using Radio Buttons, you'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 "~ignore~". 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.
Function
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.
The Click Event selects the BR Code that gets triggered whenever the user Clicks on this picture or button.
Validation
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.
Filter
The Filter Function applies to a Listview only, and is one of the most versatile functions in the ScreenIO System.
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.
Implement Read and Return keys in the Window Attribute Section because a 0 Read Key will default to a Relative Read.
Conversion
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.
Special ScreenIO Date processing
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 FileIO Date features, to allow you to specify the DATE format on disk for Date Fields.
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.
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 "five days from now", or +2w to say "14 days from now", or +3m or -1y, etc.
This also works in listviews to display the dates in any format you want, while still making sure they're numerically sortable.
Picture File
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.
Foreground Color (Header FG Color)
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.
Background Color (Header BG Color)
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.
Justification Spec
This attribute specifies the BR Justifcation Attribute to use for this screen object. The default "C" is Left Justify. You can specify:
- C - Left Justify
- CC - Center Justify
- CR - Right Justify
- CU - Force Uppercase
- CL - Force Lowercase
Set Listview
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.
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.
When you click the "Set Listview" 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.
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 "LV1") in the "Set Listview" button.
Attributes
The Attributes control attribute specifies the Control and Display Attributes to use when displaying the control. (Say that five times fast...)
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.
Tooltip Text
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'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.
User Data
This is a field you can use for any purpose you like. You can view and modify this field in your screen functions.
Protected
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'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 "P" in the Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.
Invisible
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's invisible attribute, which hides the data behind a mask of "*"s. If you wish to use the standard BR invisible attribute, you can specify an "I" in your Attributes field. This value, and all of these values, can be changed at runtime from any of your custom functions.
Listview Columns Editing
If you added a listview to your screen, then when you're done setting the listviews attributes and you press enter (or click on the listview again), you'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.
If you just added your listview, it will have an empty column in place, to give you something to click on when you'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.
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.
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.
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.
Save and Test Screen
Once you have finished adjusting the positions, appearance, and behavior of your screen controls, it is time to save your screen. Select "Save" from the File dropdown menu and your new screen is written to the disk, and its Autogenerated Screen Helper library is compiled for you.
You may now select "Test Screen" from the Screen menu, to test your new screen in a seperate BR process.
Conclusion
Your new Add/Edit screen contains everything necessary to Add and Edit records in the selected data file, and you didn't have to write any custom code at all.
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).
ScreenIO Custom Screen Functions
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.
However, I'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.
Its with ScreenIO Events and Custom Screen Functions, that the power of the ScreenIO Rapid Application Development system really begins to unfold.
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's Filter Event, or the Click events for your Buttons and Pictures, and you can have your custom code perform Validation.
Your Custom Screen Functions can modify any value in the ScreenIO System, including the Control Attributes for your individual controls. All your screen'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.
If you place controls on your screen and don'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.
By writing solid clean code, you can even reuse your Custom Screen functions, making future screen development faster even for complex powerful screens.
ScreenIO Screen Events
The screenIO system has several Events that can trigger your custom code. You will write different sorts of functions for each type of event.
Form (Screen) Level Events
ScreenIO supports eight Screen level events. These are major events triggered by the state of the screen as a whole.
Enter Event
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.
Initialize Event
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.
It is often useful to have your Initialize Event Function call your Read Event Function.
Read Event
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.
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.
Listview Read Event
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.
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.
Mainloop Event
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.
You can also place the "X" 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.
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.
See Example Mainloop Function.
Wait Event
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.
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 of Cancel, and the screen is backed out of.
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.
Locked Record Event
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.
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.
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.
Write Event
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, forcing ScreenIO to continue to process and forcing the user to fix the error before continuing.
Merge Event
This function gets called only as a result of selecting the "Dont Lock" 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.
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're newer because they clicked "save" last. It is recommended to only use the AutoMerge functionality for really simple data files.
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.
If you didn'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.
NoKey Event
This function is run when a key cannot be found. Its here so that if you don't like the standard ScreenIO "key not found" error, you can write your own.
Listview Prepopulate
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.
As of ScreenIO v91, with the introduction of fnInit_ and fnFinal_ functions, listview Preopulate is no longer the preferred method.
Listview Postpopulate
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.
Exit Event
The Exit Event happens when the screen exits. If you had to open reference data files in your screens "Enter" event, then the "Exit" event is a good place to close those same data files.
Default Event Functions
ScreenIO Now supports the specification of default event functions, which can be used by simply creating a folder called "defaults" under your "function" folder, (so "function\defaults") and placing the event functions you want in there with the appropriate name.
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 "function\defaults" folder and rename it to the correct name for the event type that you want it to be.
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.
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.
Every Screen Level event function is supported:
- enter.brs
- init.brs
- read.brs
- load.brs
- write.brs
- wait.brs
- locked.brs
- merge.brs*
- mainloop.brs
- nokey.brs*
- prelist.brs
- postlist.brs
- exit.brs
* Nokey and Merge default event functions run only when the screen does not have a specific function selected. All of the others run In addition to any function selected in the screen.
Control Specific Events
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't have any event at all.
Click Event
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.
See Example Click Event Function.
Validate Event
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 "FieldText$" in your function.
See Example Validate Field Function.
Filter Event
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.
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.
If your filter function returns a valid color code, (ex: "/#0000FF:000000" a hex code or "[HILITECOLOR]" an attribute substitution statement from your brconfig.sys), then the row is colored that color.
If your filter function returns the word "STOP", then screenio stops reading the data file and also doesn't include the record in the list. You can use this function to make listview functions run faster.
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 command to position the file pointer at the first record to display. Finally, in your filter function, when you detect that you've moved past the last record that you want to display, return "STOP".
For an example of a listview filter function, See Listview Filter Function.
fnInit_ and fnFinal_
Added in ScreenIO v91
fnInit_ and fnFinal_ are new custom functions for Priming and Clearing your listview, that are better to use then Listview Pre/Post Populate, and that exist along side your filter function, in the same file.
fnInit_ is run just prior to populating the listview, (after 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).
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'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.
When you create a new Filter Function in the newest versions of ScreenIO, they'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.
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.
See Example.
Conversion Function
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 "CNVRT$" function.
Also, if you're using BR 4.2, the Conversion function may be used with Listview Columns to natively support numeric listview columns.
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.
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.
If the conversion value is PIC or FMT then ScreenIO will not attempt to convert it back, but it will still use "val" to change numeric fields back into numeric fields.
If the conversion value is a custom function, then your custom function will need to modify "FieldText$" 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.
Valid Custom Function Types
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.
If you wish to enter any of the other types of Event Handlers, simply type them into the Event Textbox.
Link to another screen
To link to another screen, simply specify the Screen Name in Square Brackets:
Function: [CUSTEDIT] or (specify a position) Function: [CUSTEDIT(2,4)] or (pass in other values) Function: [CUSTEDIT]key$=CurrentKey$
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.
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.
You can pass Key$ and ParentKey$, Displayonly, ParentWindow, Dontredolistview, and Record.
CurrentKey$
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.
By saying "Key$=CurrentKey$" in the above example, we are telling the CUSTEDIT screen to use the currently selected listview item as the key for Editing.
ThisParentKey$
ThisParentKey$ always matches the parentkey passed into the screen. In most of your custom functions you can just use "ParentKey$" to get this value. However, when calling another screen automatically, if you want to pass the current ParentKey$ into the screen you're calling, you'll need to use ThisParentKey$.
If you say "ParentKey$=ThisParentKey$" then you'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.
Chain statement
If the first character of your function is a %, then the rest of your function is interpreted to be a chain statement.
%menu.br
This example will chain to the BR program called "menu.br".
Any single BR command
For most events, anything else you type is interpreted as a regular BR statement and executed with the execute command.
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.
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:
let ExitMode=SaveAndQuit
ExitMode is the ScreenIO variable that determines when we are done processing your screen. If you set ExitMode to the constant "SaveAndQuit" then your screen will exit and save the data on its way out.
Any valid BR Field Spec (Conversion Function Only)
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.
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'll probably want to specify a "DATE(" 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.
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.
Link to a Custom Screen Function
To link to a Custom Screen Function, use the Edit Button. Your selected Custom Screen Function will be placed within Curly Braces {}.
{AddNewCustomer}
More details about Custom Screen Functions follow.
Entering / Selecting your custom handler
To select the Custom Screen Function for a given ScreenIO Event, simply go to the correct place and click the "Edit" button. This button brings up the ScreenIO Select Custom Screen Function dialog.
At the top left you'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.
You can select any Custom Function from the list and click the "Ok" button to accept it.
Link to a Library Function
You may also link directly to a library function from any of your Screen Events. To do this, type a "#" followed by the library name and the function, separated by a ":"
#libname:fnFunctionName(parm1,parm2$,parm3)
Example: Assume your library is called "run.br" and your function is called fnRun(screenname$).
#run:fnRun('customer')
Example 2: Assume your library is called "thing.dll" and your function is called fnDoSomething(thing$,otherthing$)
#thing.dll:fnDoSomething(thing$,'constant')
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.
Writing Screen Helper Functions
To create a new Custom Screen Function, enter a name into the search box at the bottom left and click the "Add New" 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't have a default editor specified yet, then select MyEDIT or some other editor capable of working with .BRS files.
You will notice that your new blank Custom Screen Function doesn'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.
Custom Screen Function Parameters
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:
- Function$ - The Function we are Calling
- Mat F$ - The Strings for the FileIO Record Object
- Mat F - The Numbers for the FileIO Record Object
- Mat S$ - Your Screen Record Object
- Mat Form$ - Your FileIO Forms Array
- All your Screen Information
- Mat Screenio$ - Your Screen Header information (Strings)
- Mat Screenio - Your Screen Lines information (Numbers)
- mat ControlName$ - Array of the control names for all the controls on your screen.
- mat FieldName$ - Array of the Field Names for the associated fields of all the controls on your screen.
- mat Description$ - Array of the Descriptions or Caption Fields for all the controls on your screen.
- mat VPosition - Array of the Verticle Position for all the controls on your screen.
- mat HPosition - Array of the Horizontal Position for all the controls on your screen.
- mat FieldType$ - Array of the Field Types for all the controls on your screen.
- mat SpecWidth - Array of the Spec Widths for all the controls on your screen.
- mat Width - Array of the Widths for all the controls on your screen.
- mat Height - Array of the Heights for all the controls on your screen.
- mat TrueValue$ - Array of the Truth Values for all the controls on your screen.
- mat FalseValue$ - Array of the Falsehood Values for all the controls on your screen.
- mat Function$ - Array of the Function triggers for all the controls on your screen.
- mat Picture$ - Array of the Picture Files for all the controls on your screen.
- mat Parent$ - Array of the Parent Attribute for all the controls on your screen.
- mat FGColor$ - Array of the Foreground Colors for all the controls on your screen.
- mat BGColor$ - Array of the Background Colors for all the controls on your screen.
- mat Justify$ - Array of the Justification Specs for all the controls on your screen.
- mat Attr$ - Array of the Additional Attribute Specs for all the controls on your screen.
- mat Protected - Array of boolean flag indicating weather or not each of your controls are protected.
- mat Invisible - Array of boolean flag indicating weather or not each of your controls are invisible.
- mat Tooltip$ - Array of the tooltip help text for all the controls on your screen.
- mat ConvrtIn$ - Array of the conversion values for all the controls on your screen.
- mat ConvrtOut$ - Not currently used.
- mat MultiSelect - Array of values indicating weather or not your Listviews have Multiselect Enabled.
- mat Userdata$ - Array of data passed into your screen that can be used for any reason
- mat Subscripts$ - 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.
- mat ControlSpec$ - 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 "listview".
- Key$ - This is the Key that we called the screen with
- ExitMode - Set ExitMode to non-zero to cause your screen to exit.
- RepopulateListviews - Set this value to True in your function to cause ScreenIO to repopulate the listviews when its done processing your custom function code.
- RedrawListviews - 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.
- RedrawFrames - Set this value to True in your function to cause ScreenIO to redraw the each of the frames on your screen.
- RedrawScreens - Set this value to True in your function to cause ScreenIO to redraw any child screens that are a part of your screen.
- RepopulateCombo - Set this value to True in your function to cause ScreenIO to rerun all your "RepopulateCombo" functions and repopulate all the combo boxes on your screen.
- Prefix$ - Prefix for your FileIO Data File
- Currentkey$ - Currently selected key from your data file
- rec(datafile) - if you need to know the current record in the primary data file you can use the BR system function REC to discover it.
- mat SelectedKeys$ - If you have a listview with multiselect enabled, use this array to access the keys of all selected records.
- mat SelectedRecords - If you have a listview with multiselect enabled, use this array to access the record numbers of all selected records.
- mat VisibleKeys$ - All the keys that are currently visible in the listview. (v91,Requires BR 4.3+)
- mat VisibleRecords - All the records that are currently visible in the listview (v91,Requires BR 4.3+)
- mat Save_F$ - 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.
- mat Save_F - 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.
- mat Save_S$ - 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.
- mat PassedData$ - 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.
- Parentkey$ - 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.
- LockUser$ - 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.
- Datafile - This is the file number of the data file
- Window - This is the window number of the screenio screen
- FileIO Subscripts - All your fileio subscripts are set for you so you may use your file just as if you'd opened it yourself.
- ScreenIO Subscripts - Any of your screen controls that belong in MAT S$ have a screen subscript that you can use to access them.
- ScreenIO Control Subscripts - 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 "Customer" and you want to make it invisible in one of your custom helper functions, then give the command: "let Invisible(ctl_customer)=1"
- CurrentRow - 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.
- Currentfield - This is the CurFld Value of the field which the cursor is in. If you change it, it will move the cursor around.
- Currentfield$ - 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.
- DisplayOnly - 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.
- Selecting - 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.
- Only Available in Validate and Conversion Functions - 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:
- Fieldtext$ - This is the text in the field being validated/converted.
- Fieldindex (read only) - 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 "CurrentField=FieldIndex".
- ControlIndex (read only) - 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 "Invisible(ControlIndex)=1".
Accessing Control Properties from within your Helper Functions
If you wish to access any of your controls' 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're looking for, with the control name for a subscript, prefixed by "ctl_". For example, to make the customer control invisible, simply type:
let Invisible(ctl_customer)=1
#Include Statement
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:
! #Include {functionname}
in a comment somewhere in your program and the specified custom helper function will be included. The "{}"s are mandatory and are part of the syntax for specifying a Custom Helper Function anywhere in ScreenIO.
Prewritten Functions
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'll mention a couple of them here.
- deletelistviewrecord - Displays a confirmation dialog, and then deletes the currently selected record in a listview.
- deleterecord - Displays a confirmation dialog, and then deletes the current record in an add/edit screen.
- enforcerecord1 - 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.
- enterselectionlistview, filterselection, and toggleselection - These three functions work together to make listview screens where the user can toggle on and off a selection of them.
- listviewcombo[...] - 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.
- pause - 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.
- printlistview - This powerful function calls George Tisdales function to print the current listview, including current sorts and filters, to the printer. It requires George Tisdale's rtflib to be installed in a vol002 folder in your app. It can be downloaded from the Sage AX Website here: [[1]].
- exportlistviewcsv - 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).
- exportcurrentfilecsv - This export function calls the fileio Export to CSV function on the given file, for whichever columns the user wants from the file (there's a column selection dialog), and it exports just the specific rows that are currently visible in the currently filtered and sorted listview. Note: 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 "X" fields. Then use this layout for your ScreenIO screen and they will only have access to the remaining fields listed in it.
Examples
Validate Field Function
NOTE: ScreenIO has this functionality built in now, so you shouldn't need to validate your dates this way. Its only included here as an example for how a validate function works.
For more information on the proper way to work with dates in ScreenIO, see the Conversion Function section.
! function\validatedate.brs ! ! Created on 01/12/2009 ! ! This function would be placed in every field in the SageLive system that accepts a date. ! ! def fnvalidatedate(&fieldtext$;___,DateValue) let DateValue=days(fieldtext$,"mm/dd/ccyy") conv BadDateEntered let fieldtext$=date$(DateValue,"m/d/ccyy") let fnvalidatedate=1 ! Date Save Successful BadDateEntered: ! a bad date was entered. Return False so that ScreenIO Places the old value back. fnend
Listview Filter Function
! function\filtertasks.brs ! Created on 04/17/2009 ! ! fnFilterTasks - This Function Filters the Tasks List to show only ! tasks for the Current Employee that are not completed or cancelled. ! It also colors the tasks, and sets the task_status Listview Column. ! ! This function is the filter event for the Todo List listview in the SageLive System ! dim CurrentEmployee$ def fnFilterTasks$(mat f$,mat f,ParentKey$,prefix$,mat Subscripts$,mat S$) mat Employee$=("") : mat Employee=(0) read #Employee, using form$(Employee), key=f$(todo_employee) : mat Employee$, mat Employee nokey Ignore let s$(sio_EmployeeName)=Employee$(em_name) if CurrentEmployee$="" then library "timelib" : fnCurrentEmployee$ let CurrentEmployee$=fnCurrentEmployee$ end if if uprc$(ParentKey$(1:7))="SHOWALL" then if f$(todo_employee)=CurrentEmployee$ then let fnFilterTasks$="/#00FF00:#000000" else let fnFilterTasks$="/#0000FF:#000000" end if else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=0 then let fnFilterTasks$="/#33CC66:#000000" if sio_taskstatus then let s$(sio_taskstatus)="X" ! Open else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=0 and f(todo_complete)=days(date$) then let fnFilterTasks$="/#6699FF:#000000" if sio_taskstatus then let s$(sio_taskstatus)="Y" ! Completed else if f$(todo_employee)=CurrentEmployee$ and f(todo_cancel)=days(date$) and f(todo_complete)=0 then let fnFilterTasks$="/#AA0000:#000000" if sio_taskstatus then let s$(sio_taskstatus)="Z" ! Cancelled end if fnend dim Employee$(1)*1023,Employee(1),Employee def fnInit_FilterTasks let Employee=fnOpen("employee",mat Employee$,mat Employee,mat Form$,1) fnend def fnFinal_FilterTasks Close #Employee: fnend
fnInit_FilterTasks is run just prior to populating the listview, (after 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 Postpopulate).
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're cut off at the BR function name length limit at 30 characters, so fnFilterReallyLongLongName$ would become fnInit_FilterReallyLongLongNam and fnFinal_FilterReallyLongLongNa.
When you create a new Filter Function in the newest versions of ScreenIO, they'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.
These are the preferred method for populating listviews. They're better then Listview Prepopulate and Listview Postpopulate. However, Listview Pre/Post Populate will continue to work, for compatibility with existing programs.
fnInit_ and fnFilter_ were added in ScreenIO v91.
Click Event Function
! function\quickinvoiceacustomer.brs ! Created on 03/30/2009 ! ! fnQuickInvoiceACustomer - This Function automatically creates an invoice ! for a customer. ! ! This function is placed in the Click Event for the "Invoice Customer" button on the ! Customer Listview Screen in the SageLive system. ! ! It operates on the currently selected item in the listview by using the ! value of CurrentKey$ ! ! Most of the actual processing takes place in various libraries that are part ! of the SageLive system. dim Invoice$(1)*255,Invoice(1) def fnQuickInvoiceACustomer(CurrentKey$,DataFile,mat Form$) library "invclib" : fnBuildInvoiceHeader,fnAddCustomerToInvoice,fnImportCustomer, fnPrintInvoiceByData let Invoice=fnOpen("invoice",mat Invoice$,mat Invoice,mat Form$) let fnBuildInvoiceHeader(Invoice,mat Invoice$,mat Invoice) let fnAddCustomerToInvoice(CurrentKey$,mat Invoice$,mat Invoice,DataFile,mat form$) let fnImportCustomer(CurrentKey$,Invoice$(ih_id)) let fnPrintInvoiceByData(mat Invoice$,mat Invoice,1) write #Invoice, using form$(Invoice) : mat Invoice$, mat Invoice let fnCloseFile(Invoice,"invoice") let fnfm('INVCEDIT',Invoice$(ih_id)) fnend
The first function called, fnBuildInvoiceHeader, populates the Invoice Header information with the current date and the next available invoice number, etc.
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 "Billed", 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.
The next function, fnPrintInvoiceByData generates the invoice as a PDF file. It automatically detects if we're running BR 4.2 or 4.1. If we'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.
After that we write the new invoice to the database, and the file is closed.
Finally, the Edit Invoice screen is called, and the new invoice is displayed to be reviewed and emailed to the customer.
When the user is finished looking at the invoice, we return to what we were doing in the customer screen.
Mainloop Function
Now lets take a look at how to use the Mainloop Function to respond to various keys.
! function\tabsmainloop.brs ! Created on 02/21/2010 ! ! fnTabsMainloop - This Function This Function updates the Current Potential ! elements of the Screen (if they exist) ! ! This function appears in many of the SageLive screens, to enable the Windows Dropdown Menu. ! it also does a few other things for some of the screens it sits in. ! ! #Include {executetask} ! #Include {tabwindowsmenu} def fnTabsMainloop if fkey=98 then let fnProcessWindowsMenu ! Fkey 98 is Windows Menu Click if fkey=0 or fkey=201 then let fnSelect ! Fkey 0 is Enter and Fkey 201 is Double Click if sio_current_potential or sio_current_week_now or sio_current_week_poten then let fnUpdateCurrentPotential fnend def fnSelect if lwrc$(screenio$(si_screencode))="tabwork" then let fnfm("projedit",CurrentKey$) else if lwrc$(screenio$(si_screencode))="tabtodo" then if todo_function and len(trim$(f$(todo_function))) then let fnExecuteTask else let fnfm("taskedit",CurrentKey$) end if else if lwrc$(screenio$(si_screencode))="tabincome" then let fnfm("invcedit",CurrentKey$) else if lwrc$(screenio$(si_screencode))="tabexpense" then let fnfm("expnedit",CurrentKey$) else if lwrc$(screenio$(si_screencode))="tabcustomer" then let fnfm("custedit",CurrentKey$) end if if fkey<>93 then let fkey(-1) ! Reset Fkey after whatever they've done except Windows X let Function=-1 let ExitMode=0 ! Don't exit after procesing Enter Key fnend
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.
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.
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.
We're testing for fkey 201 because I also want double clicking on a listview item to preform our special "Selection" routine.
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.
FnSelect tests the value of the ScreenCode in mat ScreenIO$ to see which screen we're in, and handles the click accordingly. For example, if we're on the Customer screen, then double clicking launches the Customer Edit screen, displaying the current customer record. If we're on the Expense Screen, then we want to launch the Expense Edit screen to view or edit the Expense Record.
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.
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 "Print Bill" 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.
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.
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'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.
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'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're currently in has the Current Potential fields on it.
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.
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.
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.
ScreenIO Built In functions
ScreenIO has several built in functions for use in your events.
Mat S$
Lets go over a couple of ScreenIO Concepts one more time.
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.
let msgbox("Customer Name is "&f$(cu_Name))
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.
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$
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 "FieldName" but do have a value for "ControlName".
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.
read #CustomerFile, using form$(CustomerFile), key=f$(ih_customer) : mat Customer$, mat Customer let S$(sio_CustomerName)=Customer$(cu_FirstName)&" "&Customer$(cu_LastName)
You can use this feature to have additional input fields that the end user is able to interact with that don'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.
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.
ExitMode
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.
ExitMode can have the following values:
- ExitMode=0 .... When ExitMode is 0 the screen keeps running. You can cancel an ExitMode by setting it back to 0.
- 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.
- 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.
- ExitMode=QuitOnly .... When ExitMode is QuitOnly the screen stops running and the users data is not saved, and nothing is returned.
- ExitMode=QuitOther .... QuitOther works the same as SelectAndQuit. You can use it if you need to implement your own custom Exit logic.
- ExitMode=AskSaveAndQuit .... AskSaveAndQuit will check to see if the user has changed anything. If they have, it will ask the user if they'd like to Save or just Quit, and behave accordingly. If the user hasn't changed anything, it will just quit.
- ExitMode=Reload... will not save but will reload the screen.
- ExitMode=AutoReload
To set ExitMode in one of your functions, simply assign it a value from the list above.
ScreenIO ExitMode Constants
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're tested for by name.
let Quitonly=1 let Saveandquit=2 let Selectandquit=3 let Quitother=4 let Asksaveandquit=5 let Reload=6 let AutoReload=7
Working with Listviews
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.
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.
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'll contain every row if the listview hasn'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.
Working with the ScreenIO Loading Icon
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.
You don'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.
However, if you like, you can use these animations in your own programs, by calling the ScreenIO Animation Functions.
Changing the Loading Icon
ScreenIO comes with two different animtated loading icons: A Modern Clock and a Grandfather Clock.
If you look in the "clocks" folder that came with ScreenIO, you'll see three folders: "clock", "grandfather clock" and "kitchen clock". ScreenIO ignores all the other folders, and only looks inside the "clock" folder.
To change which clock you want to use, simply delete the contents of the "clock" folder and replace them with the contents of the one of the other folders, the one containing the clock of your choice.
Making your own clock animations
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's or gif'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.
Gif files are particularly nice to work with because they support transparency, so your loading clock doesn't have to be square.
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.
The clock.ini settings file
In your clock folders, you'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.
The five parameters, and their default values are as follows:
- ) 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're using. If your frames are very different from each other you'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.
- ) Rows (5) - The size of the animation window in Rows.
- ) Cols (10) - The size of the animation window in Columns.
- ) Color$ (inherited) - The BR color for the animation window. If present, this parameter is what goes in the "N=" part of the open statement. The default of none causes BR to use the default or inherited colors for the animation window.
- ) Border$ (no border) - The BR border string for the animation window. This can be used to add or color a BR border.
Submitting your clock animations
If you've made a nice clock, and you'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.
Keyboard Reference (Undo/Redo, Copy/Cut/Paste and more)
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.
You can also use following keyboard shortcuts any time in the ScreenIO Designer.
Ctrl-V .. Paste Controls Ctrl-X .. Cut Controls Ctrl-C .. Copy Controls Alt-Z ... Undo Alt-R ... Redo
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.
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.
Listview Column Editing Mode
You can use the following keys to reorder the columns in your listview.
Ctrl-Lf ... Move the column to the left Ctrl-Rt ... Move the column to the right
Screen Control Movement Mode
The following controls work in Control Movement Mode Only
Lf ...... Move the control left Rt ...... Move the control to the right Up ...... Move the control up Dn ...... Move the control down Space ... Make the control Wider BkSp .... Make the control narrower PgDn .... Make the control taller PgUp .... Make the control shorter Enter ... Cycle through the Control Attributes and Movement Mode Del ..... Delete the selected control from the screen Ctrl-S .. Toggle Selection for current control Ctrl-T .. Select All Textboxes Ctrl-I .. Select Inverse F7 ...... Select All Controls Esc ..... Unselect all or exit the current control F6 ...... Draw or Redraw the Movement Grid Ctrl-E .. Make all Left Edges of selected controls match the current control Ctrl-R .. Make all Right Edges of Selected Controls match the current control Ctrl-W .. Make all Widths of selected controls match the current control
Selecting Multiple Controls
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.
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.
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.
The current control will always appear in yellow, and all the controls in the currently selected group will appear in green.
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.
You can also move controls around the screen with the mouse. For more information on Mouse Movement, see the chapter on Mouse Movement.
Support for New Fileio Dates
ScreenIO Supports the 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.
There is now a new Control Attribute called "Disk Date Format" 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.
This works on listviews too, so you can now specify these two fields, to make dates show as, for example "January 24, 2018", even if they're saved on disk as "MMDDCCYY". Or, like in the following example, as "MM/DD/CCYY" even though they're saved on disk as "MDY". Specifying the date format this way, makes the listview column sort correctly in date order, no matter what the displayed format is.
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.
ScreenIO also has a new INI setting you can control:
CODE: SELECT ALL setting_DateFormatDisplay$="m/d/cy"
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.
Useful ScreenIO Functions
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's Loading Animations, for example, are available for use in any of your BR programs.
Functions to use in your ScreenIO Functions
These functions are designed to be run from one of your helper functions, to interrogate the current screen and get additional information.
fnFunctionBase
fnFunctionBase returns the Function Base of the current screen. Use it for interpreting which control was clicked on, in your Mainloop Event.
This function is designed to run from within your screen, from one of your custom functions.
Example:
if fkey-fnFunctionBase=ctl_Name then ! Name field was clicked on end if
fnIsOutputSpec and fnIsInputSpec
<boolean>=fnIsOutputSpec(FieldType$) <boolean>=fnIsInputSpec(FieldType$)
These functions are used to tell if ScreenIO would treat the given control as an Input Spec or an output Spec
They are designed to run from within your screen, from one of your custom functions.
Example:
if fnIsOutputSpec(FieldType$(ControlIndex)) then ! the current control this Validation or Click Event function is running under is a control that ScreenIO would treat as Output Only end if
- Control Index always returns the current control that a Validate or Click event function is running under.
fnGetUniqueName$
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.
Example:
let msgbox("The current control has a unique name of "&fnGetUniqueName$(mat ControlName$,ControlIndex)
- Control Index always returns the current control that a Validate or Click event function is running under.
fnFindSubscript
fnFindSubscript(MAT Subscripts$,Prefix$,String$*40)
Used to find the Subscript of the control you're searching for, when you have that controls name as a String. It searches the Subscripts array. This does the inverse of fnGetUniqueName$ above.
Example:
let index=fnFindSubscript(mat Subscripts$,"ctl_",TheNameOfTheControl$)
Functions for use in your own programs
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.
Animations
let fnPrepareAnimation let fnAnimate(;Text$*60) let fnCloseAnimation
The ScreenIO Loading Animations can be used in your own programs.
Example:
let fnPrepareAnimation for SomeReallyLongTask=1 to 1000 let fnAnimate(str$(int(100*SomeReallyLongTask/1000))&" percent complete!") ! Do some long slow thing next SomeReallyLongTask let fnCloseAnimation
fnDays
fnDays(UserEnteredDate$*255;DateSpec$*255)
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.
fnBr42 and fnBr43
fnBr42 fnBr43
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.
fnListSpec$
fnListSpec$*255(SPECIN$*255)
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.
Functions to interact with the ScreenIO Designer
These next few functions can be used to run and interface with the screenio designer directly.
fnDesignScreen
fnDesignScreen(;ScreenName$)
This function runs the ScreenIO Designer. If the optional Screen name is given, then that screen is loaded for editing.
fnSelectEvent$
fnSelectEvent$*255(Current$*255;&ReturnFkey)
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.
Update Process
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.
If you do not get this message when updating, don'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.
Your ScreenIO Helper Libraries have been moved into a new folder called 'screenio\'. 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 'include screenio\screenio.sys' to your brconfig.sys file.
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's names conflict with your data files.
If you have any questions about this process, contact Gabriel Bakker at gabriel.bakker@gmail.com.
Future Changes
A partial list of future changes for ScreenIO has been added here. If any of you have a feature in mind that you'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.
New Future Change Requests
All currently requested features have been implemented. If you have a feature in mind you'd like to see, feel free to post it here, and also please notify gabriel.bakker@gmail.com. When I have finished implementing the feature, i'll remove it from the list that you make here.
- Add your Feature
- Requests Here
Completed Future Change Requests
The following list shows some of the change requests that have been completed.
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 "Recent Changes".
- Filter Functions now include the ability to specify an "Init" and a "Final" 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).
- 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).
- Added support for FileIO'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).
- Added mat VisibleKeys$ and mat VisibleRecords to tell which rows are currently visible in the filtered listview (Requires BR 4.3+)
- Fixed the Generate Screen function to use Filter Boxes (v2.47).
- Changed Date processing so that if a year is not entered, it defaults to closest date rather then current year (v2.46).
- Fixed a bug with large fields larger then 255 bytes that was introduced with new Number processing functionality (v2.45).
- Added feature where putting "N" in for the CNVRT spec property forces them to enter only valid numbers (v2.42).
- Added ability to put in just "N" instead of having to put the whole spec "N 10" for the CNVRT spec property (v2.42).
- Fixed a bug in the Orphaned Functions list (v2.4)
Spring Conference 2017 Release, v2.3:
- Added filter boxes for Screen Selection and Function Select
- Added options to ini file to enable or disable them
setting_Load_Filter setting_FunctionSel_Filter
- Added Version Number to Comments in Program
- Made fnDesignScreen callable as a function
- Made File Layout List redraw every time so it reflects recent Layout Changes
- Fixed a bug in the "Launch Screen in New Window" code
- Added Screen Version field
- Implemeneted fnClearLayoutCash (new Fileio Feature) to get realtime Updates to File Layouts
- Fixed a compatibility issue for using Substitute to rearrange your folder structure
- Added a better message for Out Of Date Helper Libraries
- Began Tracking ScreenIO Version Carefully
Previous Changes:
- Additional Parameters in fnfm for Interacting with Screens, that get passed both in and out of your new screen.
- 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.
- True Numeric Fields in Listviews supported with BR 4.2
- Numeric Fields on regular Text Box Controls
- Mainloop event to support custom keys
- Error Handling Improvement
- Animated "Loading Icon" for populating Large Listviews
- Group Movement/Alignment of controls
- Copy and Paste of Controls from one screen to another screen
- Group Copy and Paste of Controls
- ScreenIO Helper Libraries in a special folder
- ScreenIO itself in a special folder
- Add the "-d" option to the ScreenIO Screenfld file to keep it from growing huge after some time
- Additional Field level Properties in Screenflds for Programmers to use for things
- Support for TIMEOUT and WAIT in BR - Perhaps these should be events as well
- Advanced Filtering of a Listview - using the proper index to make it run faster