m)ʔd DF"$:&$Jx(M#f~+#32%а\AldurSoft\AldurDlgOpx\Develop.txt\AldurSoft\AldurDlgOpx\AldurDlgOpx.hlp!:\AldurSoft\AldurDlgOpx.hlp\AldurSoft\AldurDlgOpx\AldurDlgDemo!:\AldurSoft\AldurDlgDemo\AldurSoft\AldurDlgOpx\AldurDlg.oxh!:\system\Opl\AldurDlg.oxh\Epoc32\Release\Marm\Rel\AldurDlg.opx!:\system\Opx\AldurDlg.opxAldurDialog OPX G.L.HoldenAldurDlg OPX Copyright Graham Holden, 2003-6 Please see the help-file \AldurSoft\AldurDlgOpx.hlp for licence information and help about using this OPX. An example OPL program, AldurDlgDemo, is also available in this directory to demonstrate some of AldurFile's uses. PmU:Dk%p @ @T[@iTable1ColA1 xColB1ColA2ColB2ColA3 xColB3ColA4 xColB4  @"DATA.APP@7!@.17J 2003-6 Graham L. HoldenOPL's ability to create dialogs makes it fairly easy to write programs with user-friendly input screens. However, you only have to see how some of the dialogs of the Psion's built-in apps behave to realise that there's a lot more to dialogs than OPL lets you get at.AldurDlg is an OPX (OPL Extension) that attempts to bridge the gap between what a Psion's dialogs can do and what a standard OPL programmer can make them do.It does this by providing the OPL programmer with a range of new functions that extend dialog functionallity into two main areas:A wider range of dialog controls can be used than those built in to OPL (e.g. you can now use range editors, radio buttons, combo boxes and others in your OPL programs).An event-driven "callback" mechanism while a dialog is on-screen, your OPL routines can be called in response to user-actions: these can validate data, launch additional dialogs or interact with the current one (changing values, dimming or hiding lines etc.).AldurDlg has been designed to replicate all the basic OPL functionallity (as well as providing lots of "extras"); although you could use AldurDlg exclusively for all dialogs in your programs, you don't have to make an "all or nothing" switch: when the standard OPL commands suffice for a dialog's needs, you can continue to use them as normal. You only need to use AldurDlg for those dialogs that need to go "beyond OPL".The next few help topics cover contact info, license terms, deployment instructions and revision history.Following these are a number of topics about general AldurDlg concepts, starting with a How to Get Help topic. These should prove useful to a new user.The remainder of the help file details all the AldurDlg functions.Note: Many of the help topics include code snippets (either usage formats, help in the transition from OPL to AldurDlg or sample code). If the 'card width' is set too narrow (or the zoom setting is too high), the code snippets will word-wrap and look odd.Tip: Use 'Tools|View Prreferences' from the menu (or press Ctrl-K) to display the card-layout dialog. Either turn off the card browser (to see the topics full-width) or increase the card width to see the code more easily.Interestingly, the View Preferences dialog shows two new tricks that AldurDlg allows you to use in your OPL programs:If the 'Show card browser' check-box is toggled off, the right-hand portion of the 'Card width' line is hidden (and you cannot move to that line).The 'Card width' editor is followed by "% of screen" so-called trailer-text that describes how the setting works.Neither of these would be possible with standard OPL, but are easy to achieve with AldurDlg!rE d" d"'h dh " d  d dj dC0 d0 dv dt] d'" " "A""9""w""""""1"5""""2""h"""""""""""""""")"S"""bBAt the time of release (September 2005), I can be reached by email on:g-holden@dircon.co.ukand my website is at:www.g-holden.dircon.co.uk/epocI also try to keep an eye on the Psion-related newsgroups, including:comp.sys.psion.appscomp.sys.psion.misccomp.sys.psion.programmerI appreciate any feedback on this package, especially bug reports for the OPX or typos in the help text. Suggestions for new features or improved clarity of the documentation are welcome, but no promises are made!I love 'dabbling' on the Psion, so any ideas for future OPXs will be given a reasonable hearing.Graham Holden.AA d"h dh"h dh" d GFBa d ""KThe copyright in AldurDlg the .SIS files and all component files is retained by the author, Graham L. Holden. The package, and/or any files within it, may only be used and distributed in accordance with the terms of this licence. If you cannot agree to be bound by the terms of the licence, you must stop using AldurDlg and delete all copies of the .SIS files and any component files from your system(s).Personal UseEverybody is granted permission to use AldurDlg to develop and run programs they develop for their own personal use, and to run any third-party programs they may acquire that make use of AldurDlg.DistributionWhere permitted, AldurDlg must only be distributed as one or more of the standard package files: AldurDlgDEV.SIS, AldurDlgDEV-WINS.SIS, AldurDlg.SIS or AldurDlg-WINS.SIS. No component file or files may be distributed outside of these packages.These four .SIS files may be freely distributed provided that no charge is made. The .SIS files may be made available for download on a website provided that no charge is made either to download the files or to join, or otherwise be able to access the files. The files may not be held on a 'pay' or commericial website unless they are freely available to all visitors without them having to pay, join or provide credit-card details.A link should be provided back to my website so that users can check for updated versions.Distribution of Developed ProgramsThe use of AldurDlg to develop any program or application that you want to distribute to others is permitted providing the following conditions are observed:If you include AldurDlg as part of your distribution, this can only be as one of the four .SIS files above, either as a standalone file, or preferably incorporated into your application's .SIS file. You may not distribute AldurDlg's component files separately. Should you choose not to include AldurDlg with your package (e.g. by relying on your users to acquire it for themselves) then the remaining conditions still apply.In your documentation and/or within the program (e.g. an 'About' screen) you must acknowledge your use of AldurDlg and include a link to my website.Programs developed with AldurDlg may be distributed for free, as shareware or commercially.I would appreciate being informed of any use you make of AldurDlg, partly for my own interest and partly so I can let people know if I release any updates.WarrantyThe software is offered "as is" with no warranty as to its suitability. Your use of it is entirely at your own risk and no liability will be accepted for any loss arising from the software's use. However, without formally committing myself to any course of action, I will attempt to rectify any faults found in the software and would be glad of any feedback concerning the software.E d" d  d d d [ d'h dh 'h dh \'h dh 'h dh  d-""$""V" "'""""" """P"" " " "" " "L"#" """""""A""{"j""#"""<"9""[" ""KAldurDlg is delivered as two pairs of EPOC Installation (.SIS) files.The first file of each pair is intended for OPL developers' use while writing applications that will make use of AldurDlg.Opx. The second file of each pair is designed for redistribution to developers' end-users as part of the application's installation process.Both of these two installation files come in two flavours. One flavour is intended for development or deployment on real EPOC devices (e.g. 5mx or Revo); the other flavour is targetted for the PC-based EPOC Emulator but is otherwise identical.DevelopmentInstall either or both of AldurDlgDEV.SIS (on a Psion) and AldurDlgDEV-WINS.SIS (on the Emulator) depending on where you intend doing your development work.The following files will be installed on the chosen installation drive of your system:\System\Opl\AldurDlg.oxh\System\Opx\AldurDlg.opx\AldurSoft\AldurDlgOpx.hlp\AldurSoft\AldurDlgOpxThe file AldurDlg.oxh provides the interface to the functions implemented in AldurDlg.oxh. The file AldurDlg.hlp describes how to use the OPX, and AldurDlgOpx is an OPL program demonstrating some of the OPX's features.To use the OPX, add the following line near the top of you OPL source code:Include "AldurDlg.oxh"and start writing your application.DistributionIf you intend distributing your application to others, you will need to ensure that your end-users get AldurDlg.opx installed on their machines. To do this, you will need to include AldurDlg.SIS with your distribution.If you are going to package your application in a .SIS file, you can simply include AldurDlg.SIS as one of its components. This will ensure that as your application is installed, AldurDlg is installed as well.If you distribute your application as discrete files, you will need to include AldurDlg.SIS among them. Your end-user installation instructions will need to direct your users to install AldurDlg.SIS.Note: On no account should you just include the AldurDlg.opx file in your package, either as a component of a .SIS file or as a standalone file. Doing this would bypass the version-control system that EPOC uses and may result in your package overwriting a newer version of AldurDlg.opx with an older one.Installing AldurDlg.SIS on your users' machines will install the following files to their chosen drive:\System\Opl\AldurDlg.oxh\System\Opx\AldurDlg.opxIf you intend to make your application available for use with the PC-based Emulator, you should follow the instructions above, but use AldurDlg-WINS.SIS in place of AldurDlg.SIS.Note: The non-'DEV' versions of AldurDlg's installation packages are provided so your end-users can use your application without cluttering up their systems with the help file and example OPL source included in the developer versions.If you think your end-users would benefit from these files, or your application is aimed at developers, feel free to include the 'DEV' version of the .SIS file in your distribution.H d"h dh"h dh" d" dF d d dWd d L$ d d d20 dh d2 d0 d<"1"" "q" "" """""N" " "8" " " "#" "=" "g" "D" ""2""" "T"""O" "`" """*" "2""" "" " "Q""" " """"""@The next few help topics cover a number of AldurDlg concepts that a new developer should make themselves familiar with so that they get a feel for the added functionality that AldurDlg can provide.The bulk of the help file covers all the AldurDlg functions. Many of these are more-or-less direct replacements for OPL equivalents (e.g. where you would use the OPL command dLong, you can now use the AldurDlg function DlgEditLong%:).The help topics for commands that fall into this category include a section on how to convert from the OPL way of doing things to the AldurDlg equivalent (under OPL AldurDlg).They often also include a section on the added features that are available with AldurDlg (under AldurDlg++), and occasionally a section noting where AldurDlg's features fall short of the OPL way (under AldurDlg--). Where present, this is usually due to limitations imposed by the OPX interface that make the replacement function slightly more cumbersome to use, rather than due to functional deficiencies.The indexing of this help file has (hopefully) been organised so that searching for the name of a standard OPL command (e.g. dChoice) will bring up the topic for the AldurDlg equivalent function (in this case, DlgChoiceList%:) as well as any other related AldurDlg functions that add to what OPL alone can do.This help file assumes a basic understanding of OPL dialogs and concentrates on the differences between AldurDlg's use of dialogs compared to standard OPL. If necessary, refer to OPL help if you need a grounding in dialog use.All AldurDlg functions will have a help topic of their own, so you can browse through them all using the Card Browser. However, in discussing how they work, it is natural and convenient to talk about two or Mmore functions in one combined topic. Where this is done, the topics for the other functions discussed will contain only basic syntax and a pointer to the "main" topic.Typographic conventionsThroughout these help topics, the following typographic conventions are used:AldurDlg procedures and OPL commands are shown in bold when mentioned in the text (e.g. dLong or DlgEditLong%:). Use the term in bold-text to search for related topics (omitting any "%:" may help).Discussion of a function's parameters will use italics for the parameter names (e.g. aLine% used in many functions).F d  d d  d d 6 d  dz df d'h dh u'h dh 8""")""~"""" " """"""" ""P""" "/""-" ""}"""""$""""."h""t"""n""N""*"""""" "Y"U"""&EThis topic covers a few basic issues that you need to know about when making the transition from OPL dialogs to AldurDlg. Some of these will be expanded upon in later topics.AldurDlg is function-based, whereas OPL uses commands. Since functions cannot have optional parameters, you sometimes have to include an explicit "0" parameter for "normal" behaviour (under OPL you would just omit it see DlgInit&: for an example).With OPL, all the commands from dInit through to Dialog, must occur in the same OPL procedure AldurDlg has no such restrictions. For more complicated dialogs, this allows common construction code to be written once and called when needed.The OPX mechanism does not allow string variables to be passed by reference (so that a function could change the contents of the variable). This makes some AldurDlg calls slightly more combersome than the OPL equivalent.If an un-trapped error occurs in a callback function (see later), the location reported when running within "Program" will usually be the DlgExecute&: function, rather than the true location of the error. This can make bug-hunting a little trickier.Although you cannot combine OPL commands and AldurDlg functions during construction of a single dialog, you can freely build some dialogs using OPL and others using AldurDlg.C d d'h dh 'h dh 'h dh 'h dh 'h dh p""8""" "" "" "")"""?" "R""9"" "e"-""7""6"""KI have tried to make the use of AldurDlg as easy as possible compared to native OPL, and I think I have succeeded in all but one area passing across string variables that have to be altered by an AldurDlg function.Note: The cause of the problem is that OPL does not allow a string variable to be passed to an OPX function by reference; this means their value cannot be upated when control returns from the dialog. Unfortunately, this is an inherent limitation of the OPL/OPX interface and not something that I can change.Luckily, the need to alter string variables only occurs in a few places: in the replacements for dEdit and dFile (DlgEditText%: and DlgFile%: respectively); and in DlgComboBox%: and DlgChoiceListString%: (both new to AldurDlg).Because a string variable cannot be passed directly to the OPX, we have to pass the address of the variable instead (using OPL's Addr() function). However, there is an additional complication in that the OPX must know the maximum length of the string, so that it can prevent the user from entering too many characters.How this is done letting the OPX know the maximum string length depends on the type of variable used (ordinary variable or array).For simple string variables (not string arrays) there isn't a problem: the address of the string allows the OPX to deduce the maximum length of the string [for the technically minded, the maximum length is stored in the byte before that given by Addr(str$)].Note: The "normal" form of all AldurDlg functions mentioned above that need to update a string variable take the address of a simple string variable. With the exception of the DlgEditText%: family of functions (see below), if you want to use an element of a string array (or a member of an OPL+ structure), you must copy it to a normal variable first (and copy it back after the dialog has executed).For DlgEditText%:, two other forms are available:DlgEditTextArray%: accepts the address of the whole array (i.e. the address of the first element) and an index into the array (to select the particular element you want to edit). As with the simple case above, the OPX can then deduce the maximum length of all elements in the array [again for the techies, the maximum length is stored in the byte before that returned by Addr(array$())].DlgEditTextMax%: accepts the address of a string and an explicit maximum length. This is mainly designed to allow members of an OPL+ structure to be edited without the need for local variables. It can also be used to impose a shorter maximum length than the string's natural length.The above may sound complicated (and it is more fuss than I would like) but for the most common case editing ordinary strings it just involves remembering to use Addr() around the string.Note: All this only applies to strings whose value is going to be altered by the OPX. Passing strings in to be used for prompts etc. doesn't require any special consideration.F d" d  d50 d d@ d d0 d2 d'h dh 'h dh  d0 d4 """" ""/"a""""" "" "" """"""T""&"""" """""" """ "!""b"""" """"" """GOne of the most powerful new features of AldurDlg is that you can ask it to call your OPL procedures when certain events occur while processing the dialog; for instance, your code can be called when the values of controls are changed, when the user moves from one control to another or when the user wants to "action" the dialog.All these "event handlers" can interact with the current dialog: reading current values; changing values; altering the visibility of lines and much more. They can also cause other dialogs to be displayed, either using OPL or AldurDlg. In the latter case, the new dialogs could raise their own callback events (almost) ad infinitum.There are a number of callbacks that potentially can be generated throughout the lifetime of a dialog; the following steps show the possible flow of control when a dialog is shown:DlgExecute&: is called from the main OPL procedure (but does not return yet).A DlgOnLoad%: callback can be raised as the dialog is about to be shown.Repeat the following steps as required:A DlgOnFocusGain%: callback can be raised whenever the user moves into a new field. If DlgCallbackOptions&: has been used, immediately after the on-load event, and/or after a focus-loss event prevents movement from one field to another.A DlgOnStateChange%: callback can be raised as the user alters the current control's value (DlgEnableStateChange%: needs to have been called on a control-by-control basis).A DlgOnFocusLoss%: callback can be raised if the user tries to move away from the current control, or (if DlgCallbackOptions&: has been used) when the user tries to "action" the dialog. The callback can then prevent the user leaving that field.A DlgOnValidate%: callback can be raised when the user tries to "action" the dialog, or (if the flag KADlgTrapEscape% was used in DlgInit&:) when they cancel the dialog. The callback can prevent the dialog from closing.DlgExecute&: returns and the main OPL procedue continues executing.E d"'h dh " d J dN dN'h dh I'h dh (' d ' d ' d 'h dh D'h dh %)"""""V" "" "B"" "<"""F"""""H"";"""X""x"""T"" " "R" "8"@An important concept with AldurDlg is the line-number or Control ID of the components of a dialog.Note: The terms (dialog) line, control, editor and element are used throughout these help topics to describe the "things in a dialog" number, text, or date editors etc., or lines of text. The only elements of an AldurDlg dialog that do not get assigned a line-number are divider-lines between elements and any buttons that may be present (this numbering is slightly different to that of standard OPL).With standard OPL, the only time you had to worry about line-numbers was in dialogs without buttons (the return value from Dialog when ENTER is pressed would be the current line-number).Line-numbers are still used in this way with AldurDlg (although the way lines are numbered has been simplified), but there is an additional arguably more important use: they give callback functions the ability to interact with the lines of the current dialog.Whenever a callback function needs to refer to a line (or control) in the current dialog, it does so using its Control ID or line-number.Simplified NumberingStandard OPL has a fairly curious (read: "odd") way of numbering the elements in a dialog. The title-bar of the dialog may or may not be counted as a line, depending on whether or not it is shown, and whether or not it is an empty string. Also, a dividing-line between controls may or may not get assigned a line-number, depending on how it is declared.With AldurDlg I have simplified this in two ways:The title-bar is never counted as a line, however it might be displayed. The first control (or text-line) in the dialog is always number one.Dividing-lines, however created, are never assigned a line-number.Both of these greatly simplify working out what line-number a given control is going to have. However, AldurDlg offers an additional feature to make things easier.Return of Control IDAll AldurDlg functions that define dialog-lines will return the Control ID or line-number of the control just defined. If you are not interested in line-numbers (or only interested in some of them), then you are free to ignore the return-code from these functions.However, for controls that you will want to refer to from callback functions, capturing the returned Control ID in a global variable has several advantages:If you ever change the layout of the dialog (add another control; more lines of explanatory text etc.), then there are no hard-coded line numbers in your code to change.If you ever construct dialogs conditionally (i.e. one or more lines may or may not be created, depending on the state of the program), then the using a global variable will capture the Control ID this time through; if you didn't do this, your callback functions would have to include a mass of logic to work out what the line-number is.Self-documentation even if all your dialogs are static, and you never change their layout, using variables in your callback code makes things much clearer than just seeing a bare line-number.ExampleThe following small example shows this idea in action: a locally-global variable (i.e. one defined in the current routine) is used to record the line-number of the integer editor; this can then be referred to in the callback routine in a future-proof, self-documenting manner.proc ExampleDialog: global didInt% local anInt% DlgInit&:( "Enter a number", 0 ) DlgOnValidate%:( "dcbValidate" ) didInt% = DlgEditInt%:( anInt%, "From 1 to 10", 1, 10 ) if DlgExecute&: print "You chose", anInt% endifendpproc dcbValidate%:( aLine%, aKey& ) if DlgGetInt%:( didInt% ) = 3 giPrint "Except three!" return KTrue% endifendpFrom (bitter) experience, the use of variables like didInt% to hold the Control IDs is much to be preferred over trying to remember line-numbers especially if you later add new lines or use optional lines..H d"'h dh "h dh" dc d0 d  d d dy d2 d'h dh C'h dh  d dQ'h dh  db d:""" "" " "" " """"""""""{"":"-"""o" "" """d"""%"""f"" "%"""h""5"""""""|"""4"""QUDynamic Controls are what I term a curious (and sometimes useful) feature that I stumbled across within Eikon (the Psion's GUI layer).It is the ability to have more than one control overlaid on top of each other, with only one visible at a time. The key point being that changes elsewhere in the dialog can alter which of the overlaid controls is seen at any one time.It's not a feature that you'll use too often, but the ability to use it when your application really demands it allows for a very sleek interface.Control GroupsTo use dynamic controls, you need to understand the concept of a Control Group the collection of controls that will all appear at the same location in the dialog.A control group is defined using DlgGroupStart%: and DlgGroupEnd%. Between these, you define the controls that you wish to overlay as normal. Once a group has been defined, you use DlgActivateInGroup%: to select which control is currently active.Note: You must use this last function before calling DlgExecute&: (or from a DlgOnLoad%: callback) to select the initially visible control. If you don't, all controls in the group will be visible on top of each other!You would then use it again from a dialog callback to change the active control as needed.Control IDs of a GroupThe return code from DlgGroupStart%: is the Control ID (or line-number) of what will be the first control in the group. The other controls in the group are numbered consecutively from this as normal (this means there will no longer be a direct correspondence between the Control ID and the physical line-number on screen, since they'll be on top of each other). So for example, in the following snippet:DlgInit&:( ... )idChoice% = DlgChoiceListZero%:( choice%, "Type", 0,0, "Int,Text,Date" )idGroup% = DlgGroupStart%:DlgEditInt%:( ... )DlgEditText%:( ... )DlgEditDate%:( ... )DlgGroupEnd%:DlgActivateInGroup%:( idGroup% + 1 )The DlgGroupStart%: would return "2", the Control ID to be assinged to the integer editor; the text editor will be "3" and the date editor will be "4". Calling DlgActivateInGroup%: with "3" (=2+1) will make the selected control (the text editor) active and all other controls in the group inactive.Not shown in the above example is the code to trigger the necessary callbacks (an on-state-change for the choice list). The corresponding snippet of callback code will be:proc dcbStateChange%:( aLine% ) DlgActivateInGroup%:( idGroup% + DlgGetChoice%:( aLine% ) )endpNote that the "Zero" version of the choice list is used so that DlgGetChoice%: returns a value of 0, 1 or 2; added to idGroup%, this gives the Control ID of the target control. As the user selects one of the three entries in the choice list, the corresponding control is activated.The full example from which these snippets are taken, together with more notes on how it works, can be seen in the help topic for DlgGroupStart%:.Other UsesAnother use I've had for dynamic controls was a generic editor-dialog for a database record. I won't show the code (it gets messy, but can be done). To keep things simple, assume all fields are edited as strings (dEdit in OPL-speak).The problem is that as you don't know in advance (i.e. at compile time) how many fields the record will have, the code will have to cope with situations when there are more fields than will fit on the Psion's screen at once.This necessitates editing the fields in "banks" or pages: if the record turns out to have 15 fields, and the current device has room for only six lines, then three pages would be needed, showing fields 1-6, 7-12 and 13-15. "Next Page" and "Prev Page" buttons would be used to move forward and back through the pages.This could be done by putting the dialog in a while-loop and redisplaying it every time one of the buttons is pressed (keeping track of a "page number" so we know which bank of fields to display). Indeed, I did do it this way to start with, but it meant the dialog was closed and re-shown every time you changed page not very "professional".With AldurDlg's dynamic controls, I was able to do this page-swapping within the same dialog. Using the figures above (15 fields, 6 visible at once), the process is essentially:Create six groups of fields using DlgGroupStart%: ... DlgGroupEnd%: (one for each visible line). Each group will have three overlaid controls (one for each of the three pages).The first group (top line of the dialog) will have editors for fields 1, 7 and 13; the second group will have editors for 2, 8 and 14. Similarly, the third group will be 3, 9 and 15.The fourth group will have editors for fields 4 and 10 as its first two entries; the third will be the equivalent of dText (with empty strings). This is because there is no field 16. Similarly, the fifth and sixth groups will have editors for 5 and 11, and 6 and 12; in both cases the third entry in each group will be another blank line.A DlgOnValidate%: callback will trap presses of "Next Page" and "Prev Page" buttons; this routine will adjust the page number and then call DlgActivateInGroup%: for each of the six groups to activate the correct control (or the blank lines).As the current "page" is changed, we can also change the title of the dialog (or, if we prefer, a text-line within it) to indicate which set of fields is currently being edited. E.g. from "Page 1 of 3 (fields 1-6)" to "Page 2 of 3 (fields 7-12)" to "Page 3 of 3 (fields 13-15)".!I d" d"h dh"'h dh " d d d d0 d[ d, db d d d>Y d d'h dh U'h dh 'h dh A"w""A" "W"!""" "v"".""""'" " " """""""k"""""M"" "@""("""""" """".""&"""""""" "o"u"""""{""R"HThe concept of Reactive Controls is intimately tied-up with that of dialog callbacks.With ordinary OPL dialogs, there is no mechanism to do anything between calling Dialog and having the dialog accepted or dismissed. Therfore, there's no possibility of altering the dialog's apearance or behaviour during that time.With AldurDlg, however, we have callbacks bits of your code that can be invoked when the user alters the value of a dialog control, moves from one control to another, or tries to accept (or dismiss) the dialog.As soon as we allow the possibility of the programmer's code being called while the dialog is active, we allow the possibility of altering how the dialog behaves we allow Reactive Controls.Exactly what is done inside your callbacks and therefore how the dialog controls react is highly variable. However, the basic operations fall into a number of categories:Choice lists can be used to select between a number of different "modes" of operation (e.g. use dynamic controls to change the type of a "search" dialog).Check-boxes can turn "on" or "off" the control(s) below them (either dimming them, or making part or all of them hidden when not applicable).You can validate the settings of individual controls as the user attempts to move from one to another.You can collectively validate the settings of the whole dialog's controls when the user tries to "action" the dialog.You can update a "calculated" field as the user alters the value(s) of other control(s).You can have "dialog driven" programs (or parts of them) where the user selects a selectable text-line (as an alternative to a menu), or presses one of a number of buttons. In these cases, the action would be trapped in a DlgOnValidate%: callback and would happen while the original dialog is still on screen.For a simple example of the type of dialog that you can now create with AldurDlg, that wasn't possible with standard OPL, press Ctrl-K now the "View Preferences" dialog of the Psion's help-viewer dims the "Card Width" control when the "Show Card Browser" is turned off (as well as having trailer text "% of screen" after the width; something else AldurDlg can do).C d"'h dh " d V d d d dgvY7'h dh s d""6"P"""""" ""J""I"""""I"H""0"""" "tIThere are two ways of validating dialog data before the user is allowed to accept the values:DlgOnValidate%: specifies a routine to be called whenever the user tries to accept (or sometimes dismiss) a dialog;DlgOnFocusLoss%: specifies a routine to be called whenever they try to move from one line to another.In both cases, the called routine can prevent the attempted action from happening. Both of these can be used to validate and reject user-entered data. The question is: when should you use which method?My guiding principle (and, I think, general good practice) dictates that preventing a user from moving away from the current control should only be used when the validity or not of the current entry can be determined with no regard to any other data in the dialog. In other words the data is intrinsically wrong or not, and altering anything else in the dialog cannot change this fact.A (contrived) example code-snippet should illustrate this:DlgInit&:( "Enter data", 0 )DlgChoiceList%:( oddOrEven%, "Number is", 0,0, "Odd,Even" )DlgEditInt%:( number%, "Value is", 0, 100 )...DlgExecute&:This fragment offers a strange way of specifying a number: the user selects whether it is to be odd or even, and then enters the value.One might be tempted to use DlgOnFocusLoss%: to call a routine that checks whenever the user tries to leave the integer editor whether the odd-or-evenness of the current value matches the current setting of the choice-list. If it doesn't, the user will not be able to leave the line and must enter a number of the right type.The problem is that this is horribly clumsy for the user to correct. Suppose that the choice-list was (erroneously) set to 'even' and the user then entered '33'; the focus-change validation won't let them continue with the rest of the dialog (or correct the odd/even setting) because 33 isn't an even number. To correct the problem, they must first enter an (incorrect) even number (so they can leave the line), then change 'even' to 'odd', then finally re-enter the number 33.In this case, it would be better to use DlgOnValidate%: to specify a validation routine that checks for consistency between the two controls when the user tries to accept the whole dialog.Even where focus-change validation makes sense, I think care should be used not to over-use it: users can feel "trapped" if they cannot move freely around a dialog.@ d"h dh" d ^t'h dh f'h dh  d;K d d"e""V"""I"."~""""("""DA pot pourri of selected tips and tricks that I've come across in my use of AldurDlg that might be useful to a new user of it:Remember that during callbacks, the OPL variables that will ultimately hold the results of the dialog will not have been updated! You must use the DlgGetInt%: family of functions if you want to inspect the current settings.Use variables to hold Control IDs (the return values of DlgEditInt%: type functions) during dialog construction; this makes keeping callbacks up-to-date easier (and is self-documenting).If you plan on updating static text on a dialog (e.g. a DlgText%: line used as a "comment"), pre-load it during dialog construction with sufficient characters so it gets given enough "width". If you don't, you'll see truncated values. Use a DlgOnLoad%: callback to set the correct initial value.When working with grouped ("dynamic") controls, you need to call DlgActivateInGroup%: before DlgExecute&: (or in an on-load callback) otherwise all controls in the group will be shown on top of each other.Remember to use DlgEnableStateChange%: after any control for which you want to receive DlgOnStateChange%: callbacks.Ideas for further tips and tricks are most welcome!>D d" d d'h dh 'h dh *'h dh 'h dh u'h dh 4" "s"f"""" " "B"" "" "w"8" "" ","A""" "e"""1"" "+QUsage:DlgInit&:( aTitle$, flags% )Begins the definition of a new dialog. Further DlgXXX: calls between this and a call to DlgExecute&: will define the contents and behaviour of the dialog.OPL AldurDlgdInit aTitle$ DlgInit&:( aTitle$, 0 )dInit aTitle$, flags% DlgInit&:( aTitle$, flags% )AldurDlg++OPL insists that all the calls to construct and launch a dialog occur in the same procedure; AldurDlg imposes no such restriction. Note: be careful, however, not to use local variables of a called-procedure, e.g.:proc one: DlgInit&:( "Dlg", 0 ) two: DlgExecute&:endpproc two: local anInt% DlgEditInt%:( anInt%, "Integer", 0, 100 )endpwould cause problems.A new flags% option, KDlgTrapEscape%, can be used when validation is in effect (see DlgOnValidate%:).After DlgInit&: has been called, a number of new functions activate new features of AldurDlg:DlgOnFocusLoss%: allows your code to be called when the use moves from one control to another (and can prevent the control being left until your conditions are met).DlgOnFocusGain%: is the counter-point to the above; it can be called as a control gains focus.DlgOnValidate%: allows your code to be called when the user tries to terminate the dialog, either by pressing ENTER, one of the buttons or, optionally, ESC. Your code can prevent the dialog from being closed, can launch additional dialogs or perform almost any other action.DlgOnStateChange%: allows, for selected controls, your code to be called when changes to a control's value are made by the user. This allows for powerful linked or dynamic controls.DlgOnLoad%: allows your code to be called just before the user is given control of the dialog. Can be used to initialise controls or display last-minute help text, for example.DlgCallbackOptions&: can be used to fine-tune how callbacks are made from AldurDlg to your code.By convention, these calls, if used, occur immediately after the DlgInit&: call, though anywhere before DlgExecute&: will work. You can also use DlgPosition%: to set the initial position of the dialog (it replaces dPosition of OPL).The following call must occur later than the control it refers to, and is generally placed immediately before DlgExecute&::DlgSetFocus%: allows the initally active control to be specified.Below are some of the new features available when constructing dialogs; see individual help topics for more detail:DlgSetChoiceSeparator%: allows the separator character for AldurDlg's replacements of dChoice to be changed (i.e. allows choices to contain commas).DlgGroupStart%: and DlgGroupEnd%: allow a group of controls to be overlaid on top of each other, with only one active at a time; see also Dynamic Controls.An increased range of controls are available, for instance DlgEditInt%: allows an integer to be edited (OPL can only edit a long); range editors (e.g. min and max; page range); radio buttons; combo-box (type-in or select).Controls can have trailer-text often used for a 'units' editor (see DlgAddTrailer%:).From "callback-routines" OPL procedures called while the dialog is still active you can build highly reactive, dynamic dialogs: you can make controls dimmed (inactive); partially or wholly invisible; you can inspect or change a control's value; and change labels (captions) and annotation text of the controls.As with OPL dialogs, a second DlgInit&: call cannot be made until after the corresponding DlgExecute&: call. However, the use of callbacks allows additional dialogs (either OPL or AldurDlg defined) to be displayed on top of the current dialog).aTitle$ is displayed on a grey background (unless KDlgNoTitle% is used).flags% can contain a combination of the following (constants in Const.oph or AldurDlg.oxh):1 KDlgButRight%Buttons appear vertically on the right (instead of horizontally at the bottom).2 KDlgNoTitle%Do not display a title bar. Prevents the dialog from being dragged.4 KDlgFillScreen%Use the full-screen for the dialog.8 KDlgNoDrag%Do not allow the dialog to be dragged by its title bar.16 KDlgDensePack%Pack the lines of the dialog closer together.$4000 KADlgTrapEscape%If a validation routine has been defined (see DlgOnValidate%:), also trap pressing the ESC key to quit.The return-code of DlgInit&: is an internal reference to the dialog being defined. Currently there is no need to take any notice of this value.O d" d"h dh"'h dh "' d "0 d" d%$'h dh  d d)'h dh 6'h dh  'h dh f'h dh ^'h dh ' d _' d ' d ' d ' d a' d h dh |h dhB' d t' d ' d ' d X' d ;'h dh  I d\ d`T6F@0 d dh""0"""""" "7""" " """"""]""r""" ""0"""" "E""""""O""""" """6"""A" "" "" "8" " "n" "" "5""$""""8""" "i""";" ""F"""" "3" "" "*""9""+" " "":" "" ""E""+"" "u"mFUsage:dlg% = DlgExecute&:Launches the dialog defined by preceding DlgInit&: and subsequent DlgXXX: commands.OPL AldurDlgdlg% = Dialog dlg% = DlgExecute&:The return code from the dialog is essentially the same as under OPL, and is determined by the following rules:If DlgSetRetCode%: has been used, this gives the return code; otherwiseIf the dialog is cancelled, the return code is zero; otherwiseIf there are buttons, the button's code is returned; otherwiseIf there are no focusable lines, the return code is one; otherwiseThe return code is the line-number of the selected line (the first line always being one).Note: These rules are slightly different from native OPL for a button-less dialog with at least one focusable control.Under OPL, if title$ is non-blank, it is counted as the first line of the dialog, effectively adding one to the return code. Somewhat bizarrely, this is true even if the title-bar is not shown the following: dInit "", KDlgNoTitle%and dInit "not-shown", KDlgNoTitle%give different results.I found this somewhat odd, even before AldurDlg was conceived; so therefore AldurDlg always counts the first line of the dialog as one and totally ignores whether or not the title-bar is empty or visible.AldurDlg++Before DlgExecute&: returns, AldurDlg may call one or more of your OPL routines; see DlgOnFocusLoss%:, DlgOnFocusGain%:, DlgOnValidate%:, DlgOnStateChange%: and DlgOnLoad%:.The function DlgSetRetCode%: can be used from a callback routine to manually set the return code from DlgExcute&:. Unless this is used with large values, the return value will always fit in a "%" variable.yG'h dh "' d " d" d" d'h dh T d d%'h dh pH' d ??C[w0 d d= d 'h dh 'h dh 2"")" """"" """ " """""6""q""""'""""""r"" " ""0""""""""" "" ""J" "^"A d" d&'h dh '8 d8\"" ""BUsage:DlgAddTrailer%:( aTrailer$ )This function new to AldurDlg allows you to add "trailer text" to any control in a dialog. This is text that appears on the right of the main control component (e.g. after the "editor" bit) that can be used to label "units" (e.g. "inches") or to provide help about the setting. For an example of trailers, see the "Tone dialing" page of the "Dialing" component of a Psion's Control Panel).Note: Call this function immediately after defining the control to which you want to add trailer-text.QA d$'h dh  dg0 d""""m""a"QA d2'h dh 8 d8+ d"+" " " """@Usage:DlgAppendChoiceList%:( aLine% )DlgReplaceChoiceList%:( aLine% )Within a callback routine, these functions allow you to alter the contents of a choice-list dialog control. A new list, or new additions to an existing list, are built up using calls to DlgChoiceListItem%: as you would when originally constructing the control. The above functions then append this new list to the end of the existing list or replace the existing list entirely.LHUsage:DlgButton%:( aLabel$, aHotKey%)Replacement for OPL's dButtons command. Use repeatedly for each button in your dialog.OPL AldurDlgdButtons "Yes", %Y, "No", %N DlgButton%:( "Yes", %Y" ) : DlgButton%:( "No", %N )AldurDlg++The most obvious difference between AldurDlg's and OPL's handling of buttons is that you can only define one at a time with AldurDlg you need multiple calls to DlgButton%: for multiple buttons (this is because OPX routines cannot have a variable number of parameters).At first sight this might seem more cumbersome, but is actually much more flexible, as should be obvious if you've ever wanted a dialog with optional buttons. In the slightly contrived example below:if option_A_allowed% AND option_B_allowed% dButtons "ESC", -27, "Option A", %A, "Opption B", %B, "Default", 13elseif option_A_allowed% dButtons "ESC", -27, "Option A", %A, "Default", 13elseif option_B_allowed% dButtons "ESC", -27, "Option B", %B, "Default", 13else dButtons "ESC", -27, "Default", 13endifbecomes:DlgButton%:( "ESC", -27 )if option_A_allowed% DlgButton%:( "Option A", %A )endifif option_B_allowed% DlgButton%:( "Option B", %B )endifDlgButton%:( "Default", 13 )If there was a third optional action that could be performed, the OPL would become even more complicated. It may (justifiably) be argued that dialog box buttons shouldn't get more complicated than this, but even avoiding repeating all the labels (and therefore forgetting to change them all) seems worth it to me.AldurDlg offers another way of implementing a dialog like the above: using DlgSetDimmedButton%: it is possible to have inactive buttons; the above example would become:DlgButton%:( "ESC", -27 )DlgButton%:( "Option A", %A )DlgButton%:( "Option B", %B )DlgButton%:( "Default", 13 )DlgSetDimmedButton%:( %A, NOT option_A_allowed% )DlgSetDimmedButton%:( %B, NOT option_B_allowed% )Here, all four buttons would always be visible (presenting the user with a consistent interface), but not all of them would be active.The normal OPL modifiers (to hide the key-label or to not need CTRL) work as normal.eD'h dh " d"h dh" d" d" d('h dh X d dT 'h dh 9 ;h dh'h dh U"!""":""" "$""P""" "b"" """C""J"IUsage:DlgCallbackOptions&:( newOptions& )Allows control over a number of lower-level options that dictate how callback functions operate. The newOptions& replace the existing options currently in effect; the return value of the function is the set of old options being replaced (so that you can restore them later, should you wish).The OPX actually maintains two sets of options:A default set that is global to the whole program, andA current set that is local to the current dialog.Whenever DlgInit&: is called, current global default options are used as the newly-created dialog's current set of options.If DlgCallbackOptions&: is called during dialog construction (i.e. between DlgInit&: and DlgExecute&:) or from a callback, then it will update the current options of the dialog (and return the current dialog's old options).If DlgCallbackOptions&: is called at any other time, then it will update the global default options (and return the old global defaults).The initial global setting (and therefore that inherited by all dialogs) is zero (i.e. all the options below will be turned off).newOptions& can be any bit-wise ("OR") combination of the following flags (constants in AldurDlg.oxh):1 KAdlgFocusGainOnLoad&If focus-gain events are requested (through a call to DlgOnFocusGain%:) then an additional event will occur as the dialog is created. This hapens after the on-load event. Normally, no event is triggered as the dialog opens.2 KADlgFocusLossOnClose&If focus-loss events are requested (through a call to DlgOnFocusLoss%:) then an additional event will occur as the user accepts the dialog (but not if they cancel it). This happens before the on-validate event. Normally, no event is triggered as the dialog closes.4 KADlgSuppressInfoMsg&Attempts to supress the "info messages" about incorrect input that may be produced when typing into a numeric editor (including time, date and range editors) that is being monitored for on-state-change events. You may still see a flicker for some messages.8 KADlgNoFocusChangeIfNoMove&If there is only one "active" (e.g. visible, non-dimmed, focusable) line in the dialog, this option supresses focus-loss and focus-gain callbacks. Normally, focus-loss/gain events would be generated even though the line doesn't change.16 KADlgFocusGainAfterRefusal&Causes a focus-gain event (with direction of zero) to be generated after a focus-loss callback that refuses to let the user leave the curent field. Normally, no focus-gain callback is generated after a such a refusal.eF d"0 d" d+'h dh % d07'h dh 3'h dh | d d  d dg d0 d$0 d -"$"f" """"."""*" " """0"""""4" "" ".""F"""=""/"L""2" "M" ""N"""O"""A d0'h dh = d d:'h dh  ")"."" """ """"KUsage:DlgChoiceList%:( BYREF aChoice%, aPrompt$, aFlags&, aWidth%, aChoiceList$ )DlgChoiceListZero%:( BYREF aChoice%, aPrompt$, aFlags&, aWidth%, aChoiceList$ )DlgChoiceString%:( aStrAddr&, aPrompt$, aFlags&, aWidth%, aChoiceList$ )DlgChoiceStringZero%:( aStrAddr&, aPrompt$, aFlags&, aWidth%, aChoiceList$ )See also: DlgChoiceListItem%: DlgSetChoiceSeparator%: DlgRadioButton%: DlgComboBox%: DlgAppendChoiceList%: DlgReplaceChoiceList%: DlgChoiceListCount%:These functions provide a more flexible alternative to OPL's dChoice command. Associated functions add radio-buttons and combo-boxes to the OPL Programmer's repertoire.OPL AldurDlgAt its simplest:dChoice aChoice%, aPrompt$, aList$ DlgChoice%:( aChoice%, aPrompt$, 0,0, aList$ )For the equivalent of OPL's ",..." construct (allowing choices to be split between more than one call), see below.AldurDlg++EPOC32 (i.e. Psion 5 onwards) extended the dChoice command so that choice-lists can be built up in multiple calls. However, the way it does this is very unwieldy, in that you have to know when you're on the item before last (so you can omit the ",..."). Also, it doesn't allow choice-items to contain a comma (",") as this is always used as an item separator. AldurDlg addresses both these issues.DlgSetChoiceSeparator%: can be used to change the separator character (or to have no separator).Multiple DlgChoiceListItem%: calls can be made to build up the choice list; each can contain zero, one or more choice-items. For simple choice lists, there is no need to call this routine, simply pass the options in the aChoiceList% parameter to DlgChoiceList%:.A final DlgChoiceList%: call actually defines the choice-list line in the dialog box. Its aChoiceList% parameter can also specify zero, one or more additional items.The DlgChoice...Zero%: versions of the functions number the choices from zero instead of one (OPL always numbers choices from one with dChoice).The DlgChoiceString...%: versions return the final selection as a string instead of the choice-index (the ...Zero%: version is still needed if the current index is required during a callback).Note: With the last two variants, as with DlgEditText%:, the string to hold the result must be passed in as an address. At present, only the passing of simple (non-array) strings is supported (others must be copied to a local variable first).AldurDlg also provides the ability to alter a choice-list while a dialog is active: from a callback function, you can append new choices to the list or relace the list entirely.width% gives the width of the choice-selector in characters; if zero then the width of the longest item is used (this mimics OPL). This can be useful if one entry is much longer than the others, and you want to limit the width used. Alternatively, it can be used to "reserve" space if you're going to be changing the selections during callbacks.ZXZ Can't remember what flags% does!H'h dh " d" d9'h dh 8 d8 d dU'h dh s'h dh  'h dh a'h dh 'h dh 'h dh 'h dh 'h dh 0 d'h dh \ d%'h dh 8"2" ""=""f""" """"/"""R"+""9""""J" """ """"""D" "@"""q"""""R" "N""$" """""V""""EUsage:DlgChoiceListItem%:( aChoiceList$ )DlgRadioButtonItem%:( aChoiceList$ )See also: DlgChoiceList%: DlgSetChoiceSeparator%: DlgAppendChoiceList%: DlgReplaceChoiceList%: DlgChoiceListCount%:This function (with two alternate names) builds up a list of items for use with choice-lists (OPL's dChoice) or two new controls: radio-buttons and combo-boxes (combination of an editor and drop-down list).The aChoiceList$ parameter specifies one or more items to be added to an internal list. By default, the item separator is a comma (",") as in OPL, but this can be changed with DlgSetChoiceSeparator%: to any other character (or to no separator, in which case the whole string becomes one item, whatever it contains).When ready, you use DlgChoiceList%:, DlgRadioButton%: or DlgComboBox%: to define a dialog control using the current list (optionally specifying one or more additional list items).Note: Depending on your fancy, or the natural logic of your code, you can either: specify all list-items using this function; specify all items in the control-creating function (one of the three mentioned above); or a mixture of the two.As well as allowing the initial choice-list to be constructed, this function can also be used during callback routines. The list so constructed can then be used to append-to (DlgAppendChoiceList%:), or replace (DlgReplaceChoiceList%:), an existing list in other words, a list can be changed on-the-fly.C dP'h dh t8 d8 d= d d0 d2 d"I" "j"d""d"" """u"""""" "n"""""""H"QA dP'h dh 8 d8` d"I" """"="-AUsage:DlgChoiceStringZero%:( aStrAddr&, aPrompt$, aFlags&, aWidth%, aChoiceList$ )See also: DlgChoiceList%:Creates a choice-list (like dChoice) but returns the selection as a string instead of an index. The current index (accessible from callback functions) is numbered from zero instead of one.@ dT'h dh 8 d8 d"M" ""@"""QA dW'h dh 8 d8\ d"P" """"9"DUsage:DlgComboBox%:(aStrAddr&, aPrompt$, aWidth%, aChoiceList$ )See also: DlgChoiceList%: DlgChoiceListItem%: DlgSetChoiceSeparator%:Similar to a choice-list, except that a combo-box control is created, allowing either a pre-defined string to be selected, or a new one to be entered by the user.A list of pre-defined choices is built the same way as for a choice-list. The difference is that the final control also features a text-editor so that free user-input may be accepted as an alternative to the pre-defined choices.The initial contents of the edit-box (i.e. what's visible to the user) comes from the string whose address is passed in (which need not occur in the list of choices). However, DlgSetComboBoxFromList%: can be used to set the initial string from one of the elements in the list.Note: DlgChoiceListItem%: and DlgRadioButtonItem%: are different names for the same routine the list that is built is used for either choice-lists (DlgChoiceList%:), radio buttons (DlgRadioButton%:) or combo boxes (DlgComboBox%:).Note: As with DlgEditText%:, the string to hold the result must be passed in as an address. At present, only the passing of simple (non-array) strings is supported (others must be copied to a local variable first).C d" dC'h dh F8 d8 d0 d 0 d"<" "<"""M""""d""""" """" "" BUsage:DlgDismissDialog%:Called from within a DlgOnValidate%: callback, this routine effectively forces a "cancel" action for the dialog in other words, the dialog will close and the original OPL variables will not be updated. Its use will be ignored if the DlgOnValidate%: routine returns KTrue% (i.e., if the dialog should not be closed).Note: Should only be called during a DlgOnValidate%: callback.For an example of its use, see the second variant of dcbTriangleValidate%: in the examples for DlgOnValidate%:.B d'h dh ? d ?0 dp d""""""-""""-"""" "5"""""BUsage:DlgDividerAfter%:Can follow any other dialog-construction line to draw a dividing line between two controls. OPL AldurDlgdText "", "", KDTextSeparator% DlgDividerAfter%:AldurDlg++For standalone dividing lines between two non-text controls, the syntax is nicer than the equivalent OPL.For a dividing line after a text-line (using DlgText%: or DlgAnnotate%:, the equivalents of dText) you can still use the KDTextLineBelow% option (=$200).Unlike with OPL, a dividing line never counts as a line-number, whether it has been defined on its own with KDTextSeparator% or through the use of KDTextLineBelow% (with OPL, the former counts as a line, whereas the second doesn't see the note for DlgText%:).'D d" d"'h dh " d 'h dh ] d4'h dh  j'h dh  'h dh  """" """"-" "" """"""!""F""""W" ""BUsage:DlgEditBuffer%:( aBuffer&, aPrompt$, aWidth%, lines%, aMaxLength&, flags& )See also: DlgEditText%: DlgEditTextEx%:Offers a replacement for OPL's dEditMulti command for editing large blocks of text over multiple lines.OPL AldurDlgDlgEditBuffer%: directly replaces dEditMulti; the only difference being the additional flags% parameter; use zero for this if you want an exact duplicate:dEditMulti aBuffer&, aPrmopt$, aWidth%, lines%, aMaxLength% DlgEditBuffer%:( aBuffer&, aPrompt$, aWidth%, lines%, aMaxLength&, 0 )AldurDlg++The flags& parameter provides additional features to control the editor; see DlgEditTextEx%: for the options.C d" d S'h dh (8 d8h d d'h dh 'h dh  n'h dh "L" """ "?""" """ "+"">";""G"""d"IKUsage:DlgEditDate%:( BYREF aDate&, aPrompt$, aMin&, aMax& )DlgEditDateNoPop%:( BYREF aDate&, aPrompt$, aMin&, aMax& )DlgEditTime%:( BYREF aTime&, aPrompt$, flags%, aMin&, aMax& )DlgEditTimeAndDate%:( BYREF aDate&, BYREF aTime&, aPrompt$, aBetween$, flags%, aMinDate&, aMinSecs&, aMaxDate&, aMaxSecs& )DlgEditTimeAndDateNoPop%:( BYREF aDate&, BYREF aTime&, aPrompt$, aBetween$, flags%, aMinDate&, aMinSecs&, aMaxDate&, aMaxSecs& )Define one of a number of variants of date and/or time editors. The two Dlg...NoPop%: versions disable the pop-up calendar for dates (normally shown when TAB is pressed).OPL AldurDlgdDate aDate&, aPrompt$, aMin&, aMax& DlgEditDate%:( BYREF aDate&, aPrompt$, aMin&, aMax& )dTime aTime&, aPrompt$, flags%, aMin&, aMax& DlgEditTime%:( BYREF aTime&, aPrompt$, flags%, aMin&, aMax& )AldurDlg++ZXZ!OPL doesn't show am/pm for duration editors;zeroes components that aren't used (hours/seconds)The calendar pop-up can be disabled for date editors.A combined time-and-date editor can be used.The time and date editors will obey the current "locale" settings (see "International Settings" from the Control Panel). These affect the format of a date; whether to use a 12 or 24 hour clock etc.All the constants defined in Const.oph for controlling a dTime editor can be used (as the flags% parameter) for editors that include time:As "one or the other" selectors:0 KDTimeAbsNoSecs%The default; hours and minutes but no seconds.1 KDTimeAbsWithSecs%Hours, minutes and seconds.2 KDTimeDurationNoSecs%Duration editor; hours and minutes but no seconds.3 KDTimeDurationWithSecs%Duration editor; hours, minutes and seconds.Alternatively, cobine one or more of the following flags:1 KDTimeWithSeconds%Include a "seconds" field.2 KDTimeDuration%Edit a duration instead of an absolute time.4 KDTimeNoHours%Omit the "hours" field.8 KDTime24Hour%Force 24-hour format irrespective of what "International Settings" say.In addition, the following constants are defined in AldurDlg.oxh to provide useful minimum and maximum values:KMaxTime& (= &1517f = 86399)Maximum time-of-day (i.e. 11:59:59 pm) in seconds.KMaxDate& (= &2d247f)Not actually the largest date that can be handled, but the largest that doesn't stray into odd-looking five-digit years (i.e. 31st Dec 9999).KReallyMaxDate& (= &6525121)This really is the largest date that it seems EPOC can handle; 27th Dec 292,276. I think it's safe to say that the Psion won't be around long enough for us to worry about the "Y300K" problem!KYearZero& (= -&a96d5)Represents 1st Jan 0000.Note: Although the Psion can handle five or more digit dates, some of its messages get confused (sometimes only showing the first four digits).Similarly, it can handle negative dates, but the display and some messages aren't ideal.Note that these are limitations with EPOC; not with AldurDlg..[E d"'h dh " d"0 d"8 d8" d'h dh  d d'h dh  d6- d!B1KG:0?)Xo dP00 dY?8 d8""I" "V""" "$""b"">"" """""+"4" "/"""4"""QA dB'h dh 8 d81 d";" """"'"PAUsage:DlgEditFloat%:( BYREF aFloat, aPrompt$, aMin, aMax )DlgEditReal%:( BYREF aFloat, aPrompt$, aMin, aMax )Defines a floating-point number editor. DlgEditReal%: and DlgEditFloat%: are synonyms use which ever name you prefer.OPL AldurDlgdFloat aFloat, aPrompt$, aMin, aMax DlgEditFloat%:( aFloat, aPrompt$, aMin, aMax ) B dp'h dh y d dV'h dh  "i")" """0""" "#""/"AUsage:DlgEditInt%:( BYREF aVar%, aPrompt$, aMin%, aMax% )DlgEditLong%:( BYREF aVar&, aPrompt$, aMin&, aMax& )Defines an editor for either integer (16-bit, "%") variables or long (32-bit, "&") variables. In both cases, minimum and maximum values must be given.OPL AldurDlgdLong aLong&, aPrompt$, aMin&, aMax& DlgLong%:( aLong&, aPrompt$, aMin&, aMax& )AldurDlg++DlgEditLong%: directlry replaces dLong; the new function DlgEditInt%: allows editing integer ("%") variables directly.kB d" d" dp'h dh  dT'h dh  w'h dh  "i""" "$""," "," "2"QA d<'h dh 8 d8 d"5" " """"BUsage:DlgEditRange%:( BYREF aLower%, aSep$, BYREF aUpper%, aPrompt$, aMin%, aMax% )DlgEditRangeLong%:( BYREF aLower&, aSep$, BYREF aUpper&, aPrompt$, aMin&, aMax& )Defines a range editor for either integer (16-bit, "%") variables or long (32-bit, "&") variables. Two numbers are shown with the text aSep$ between them. Both numbers must be between aMin and aMax, and aLower must be less than or equal to aUpper. For stricter rules (i.e. they cannot be equal; different minima or maxima) use a validation routine (see DlgOnValidate%:).AldurDlg++New to AldurDlg, these functions allow you to edit a range (e.g. you could control a range of pages to be printed with:DlgEditRange%:( start%, "to", end%, "Page range", 1, maxPages% )B d"h dh" d'h dh v d x'h dh A""""-""""""""l"""""i"A d" dY'h dh 8 d8&"R" ""@Usage:DlgEditText%:( aStrAddr&, aPrompt$, aWidth% )DlgEditTextArray%:( aStrAddr&, anElement%, aPrompt$, aWidth% )DlgEditTextMax%:( aStrAddr&, aMaxLength%, aPrompt$, aWidth% )See also: DlgEditTextEx%: DlgEditBuffer%:These three functions allow editing of string (text) entries. Together, they replace OPL's dEdit command. See the "See Also" functions above for AldurDlg's replacement for dEditMulti and a way of creating a multi-line editor without the hassle of using buffers.OPL AldurDlgAlthough AldurDlg's functions offer more power than the standard OPL ones, they are slightly more cumbersome to use this is because an OPX does not allow a string variable that is passed in as a parameter to be changed. Instead, we have to pass the address of the string into the routines; it is further complicated because the OPX also needs to know the maximum length of the string.What this means in pactice is that you must use the right form of the function depending on whether you want to edit a simple string variable, an element of a string array, or an OPL+ structure element (this last option is not possible with OPL commands).Simple String:local strVar$(30)...dEdit strVar$, aPrompt$ DlgEditText%:( Addr( strVar$ ), aPrompt$, 0 )dEdit strVar$, aPrompt$, aWidth% DlgEditText%:( Addr( strVar$ ), aPrompt$, aWidth% )Array Element:local strArray$(10,30)...dEdit strArray$(i%), aPrompt$ DlgEditText%:( Addr( strArray$() ), i%, aPrompt$, 0 )dEdit strArray$(i%), aPrompt$, aWidth% DlgEditText%:( Addr( strArray$() ), i%, aPrompt$, aWidth% )For a simple string variable, you pass in its address; to edit an element of a string array, you pass in the base address of the array and the element number you want to edit.Using zero for the aWidth% parameter gives the same effect as omitting the parameter under OPL (i.e. the width will be based on the string's maximum length).AldurDlg's equivalent of dEditMulti is DlgEditBuffer%: (covered in another help topic). There is also the DlgEditTextEx%: family of functions that allow multi-line editing without using buffers.AldurDlg++As well as the two forms above (for editing simple string variables and elements of a string array), AldurDlg offers a third form suitable for editing strings within an OPL+ structure (these couldn't be directly edited in OPL, and would have needed copying to a local variable). For example:struct myStruct ... str$(30)ends...local pStruct&...DlgEditTextMax%:( pStruct& + OFFSET(myStruct,str$), 30, aPrompt$, 0 )This form can also be used to impose a shorter maximum length on the input than the string allows; the following would only allow 30 characters to be entered (in the width needed for 20):local temp$(255)...DlgEditTextMax%:( Addr( temp$ ), 30, aPrompt$, 20 )Note: AldurDlg also offers three DlgEditText...Ex%: variants; these offer much of the benefit of dEditMulti without the hassle of dealing with buffers. See the topic on DlgEditTextEx%: for more details.Gh dh" d" d" d" d'h dh *8 d8 d d'h dh 'h dh 'h dh  d d %'h dh I0 d ."" " "\""2""" "P""" " """""""""""""" """5""J"e"""""""." "?"""A d" dF'h dh (8 d84"?" ""A d" dX'h dh (8 d8l"Q" ""dHUsage:DlgEditTextEx%:( aStrAddr&, aPrompt$, aWidth%, lines%, flags& )DlgEditTextMaxEx%:( aStrAddr&, aMaxLength%, aPrompt$, aWidth%, lines%, flags& )DlgEditTextArrayEx%:( aStrAddr&, anElement%, aPrompt$, aWidth%, lines%, flags& )See also: DlgEditText%: DlgEditBuffer%:These three functions provide extended options over the three non-"Ex" variants of AldurDlg. As with the "bare" versions, different forms are provided depending on whether you're editing a simple string variable, an element of a string array, or an OPL+ structure element. See the help topic for DlgEditText%: for more details of when to use each variant.All variants offer two extra parameters over the non-"Ex" versions: lines% specifies how many lines of text should be used, thus allowing multi-line editors without having to use buffers; flags& is a combination of one or more of the following values (defined in AldurDlg.oxh; not all combinations are sensible):&4 KADlgWidthInPixels&aWidth% specifies the width in pixels (instead of characters).&8 KADlgNoAutoSelection&Does not automatically select any existing text. Cursor starts at beginning of any existing text.&10 KADlgJustAutoCurEnd&Positions cursor at end of any existing text. Implies KADlgNoAutoSelection& if not present.&20 KADlgNoWrap&Text does not wrap to fit box; Use Shift-Enter to add new-line.&80 KADlgNoHorizScrolling&Does not automatically auto-scroll horizontally. Not very useful with KADlgNoWrap&.&1000 KADlgAlwaysShowSelection&Always shows highlighted text, even if not the active control.&2000 KADlgReadOnly&Does exactly what it says on the tin (cannot edit, only scroll around).&8000 KADlgAllowUndo&Allows use of an undo-buffer (Ctrl-Z performs limited undo).&10000 KADlgNoLineOrParaBreaks&Prevents Shift-Enter from being used.Note: Although these functions allow multi-line editors to be used without the complication of using buffers, do remember that you are still editing string variables, so the maximum length that can be entered or edited is 255 characters.If you need more space than this, you must use DlgEditBuffer%: (AldurDlg's replacement for dEditMulti).E0 d" d'h dh (8 d8f d9 dV0 d|v0 dQ0 dp0 d_]S0 dF0 d0 dh8 d8)"" ""S""" "/"D""" "&"""8"P"""4" ""b" ""4""")" """"/""""" ""A d" dE'h dh (8 d8S">" "" AUsage:DlgEditTextMaxEx%:( aStrAddr&, aMaxLength%, aPrompt$, aWidth%, lines%, flags& )See also: DlgEditText%: DlgEditText%:Edits a string with an imposed maximum length, or an element of an OPL+ structure, that allows extended options, including multi-line text.A d" dW'h dh &8 d8"P" ""QA dE'h dh 8 d8 d">" """""A d" d'h dh 8 d86"|" ""A d" d'h dh 8 d8["" ""FUsage:DlgFile%:( aFilenameAddr&, aPrompt$, aFlags&)Replacement and enhancement for OPL's dFile command.OPL AldurDlgdFile aFile$, aPrompt$, flags% DlgFile%:( Addr(aFile$), aPrompt$, flags% )AldurDlg++If aPrompt$ is left empty (""), then Epoc's standard prompts ("Name", "Folder" and "Disk") will be used.Additional flags are available to hide one or more of the three components of the file-selector (see below).AldurDlg--As with DlgEditText%:, the string to hold the result must be passed in as an address. At present, only the passing of simple (non-array) strings is supported (others must be copied to a local variable first).In addition to the normal flags defined in Const.oph for dFile, the following (defined in AldurDlg.oxh) can be used to hide one or more components of the selector:&1000 KADlgNoDriveSelector&&2000 KADlgNoFolderSelector&&3000 KADlgNoDriveOrFolder&In addition the following flag can be used to set the width used by the file/folder component of the selector:&10000 KADlgSelectorWidth&Multiply the above constant by the width in characters and add into the flags& parameter, e.g.:DlgFile%:( Addr(file$), "", 30*KADlgSelectorWidth& + ... )Note: Each of the (normally) three components of the file-editor take up a line of the dialog. If DlgFile%: was used first, it would take lines 1, 2 and 3 (for the name, folder and disk respectively) and the next control would be line 4. Obviously, this will change if either the drive and/or folder are omitted.When getting or setting the filename (DlgGetFile$: or DlgSetFile%:), you can use the ID from any of the component lines. If a DlgOnStateChange%: callback has been enabled, the line-number passed in is of the specific component that has just been changed.>F d"'h dh " d"h dh" d6'h dh 5 d dN'h dh  i'h dh m 'h dh  do` d;;0 d d&"/"&"" """ ""","""^"" ""+" """" ">"H""""]" ""&" "" "=""o"BUsage:button$ = DlgGetButtonText$:( aButtonID% )DlgSetButtonText%:( aButtonID%, aButton$ )These two functions allow button-text to be retrieved and set.See DlgSetDimmedButton%: for notes on the correct value to use for aButtonID%.Tip: Not specific to AldurDlg (it also works with OPL buttons) but you can spread button-text over more than one line by including CHR$(10) (the ASCII code for a line-feed) within the string.Note: At present, a button will not resize as its label text is changed; if you plan on altering button-text, make sure you reserve as much space as may be needed when you first create the button. You can then use a DlgOnLoad%: callback to set the correct initial value. The example for DlgSetTextLabel%: demonstrates this principle. C d]'h dh ? dO d0 dP0 d"V"" """"+" """""f""5""""" "="""7BUsage:caption$ = DlgGetCaption$:( aLine% )DlgSetCaption%:( aLine%, aCaption$ )These two functions allow the caption of a control to be retrieved and set. The caption (or prompt) is the text in the left-hand column of a dialog.Note: At present, the dialog will not resize as the caption is changed; if you plan on altering the caption, make sure you reserve as much space as may be needed when you first create the dialog. You can then use a DlgOnLoad%: callback to set the correct initial value. The example for DlgSetTextLabel%: demonstrates this principle.A dQ'h dh  dO0 d "J"""q""""" "="""@Usage:line% = DlgGetFocus%:See also: DlgSetFocus%:Returns the line-number (or Control ID) of the active control.Note: The first line within the dialog is always number 1, whether or not there's a title bar. Divider-lines between controls are never counted as distinct line-numbers.sA d" d'h dh 8 d8?0 d"" """"KUsage:textLabel$ = DlgGetTextLabel$:( aLine% )DlgSetTextLabel%:( aLine%, aTextLabel$ )These two functions allow the text-label to be retrieved and set. This only applies to "text-lines" of a dialog those created with either DlgText%: or DlgAnnotate%: and apply to the right-hand part of the control.Note: At present, the dialog will not resize as the text-label is changed; if you plan on altering the text-label, make sure you reserve as much space as may be needed when you first create the dialog. You can then use a DlgOnLoad%: callback to set the correct initial value.ExampleThe following example shows how a dynamic text-label can be used to enhance a choose-file dialog. It is assumed that GetFileDetailsString$: returns a string giving details of the file passed to it; e.g. size, date it was modified, comments from some database. As the user cycles through the files, the details for the current file are shown.It also illustrates the principle of pre-loading text that is going to be changed with a long-enough string to cater for all variants. In this case annotation-text is shown, but the same idea applies equally to changing captions, trailers, button-text or the title-bar.proc ChooseFile: local file$( 255 ) file$ = "C:\*.*" DlgInit&:( "Choose file", 0 ) DlgOnLoad%:( "dcbChooseFileLoad" ) DlgOnStateChange%:( "dcbChooseFileChange" ) DlgFile%:( Addr(file$), "", 0 ) DlgEnableStateChange%: DlgAnnotate%:( "Details", Rept$( "M", 40 ) ) if DlgExecute&: ProcessFile:( file$ ) endifendpproc dcbChooseFileLoad%: dcbChooseFileChange%:( 1 )endpproc dcbChooseFileChange%:( aLine% ) local details$( 255 ) details$ = DlgGetFile$:( aLine% ) details$ = GetFileDetailsString$:( details$ ) DlgSetTextLabel%:( 4, details$ )endpNotesUses DlgOnStateChange%: to react as the user browses around files. Note that the aLine% parameter could be 1, 2 or 3 depending on whether the user changes the file, path or disk selection.The empty prompt string for the DlgFile%: call tells it to use the standard "File", "Path" and "Disk" for the three dialog lines.The "Details" line uses DlgAnnotation%: instead of DlgText%: so that more text can be fitted into the same space.Using Rept$, the text-label is initially set to a long string of "M"s; this ensures that the control is wide enough for whatever the text is set to in the future.The example also uses DlgOnLoad%: so that the details-string for the initially-selected file can be shown as the dialog is displayed. This is done by "faking" a call to the state-change callback as though the user had changed the selection. The initial string of "M"s will never be visible.For brevity, the callback functions hard-code the line-numbers of the controls they deal with. It is better practice to use global variables in ChooseFile: to hold the Control IDs.The function GetFileDetailsString$: not shown is assumed to return some descriptive string for the file passed to it.F d"h dh" d" dY'h dh  d0 d` d4'h dh 'h dh r'h dh 'h dh %'h dh 'h dh z'h dh *"R"" "e" "" "4""""" ",""v"""""" " "Y""" " "6""""" """ "" ""W"bBUsage:trailer$ = DlgGetTrailer$:( aLine% )DlgSetTrailer%:( aLine%, aTrailer$ )These two functions allow the trailer of a control to be retrieved and set. The trailer is optional text (see DlgAddTrailer%:) that can appear to the right of the main component of a control.Note: At present, the dialog will not resize as the trailer is changed; if you plan on altering the trailer, make sure you reserve as much space as may be needed when you first create the dialog. You can then use a DlgOnLoad%: callback to set the correct initial value. The example for DlgSetTextLabel%: demonstrates this principle. B dQ'h dh  dO0 d"J"""J""C""""" "="""HUsage:int% = DlgGetInt%:( aLine% )long& = DlgGetLong&:( aLine% )lower% = DlgGetRangeLower%:( aLine% )upper% = DlgGetRangeUpper%:( aLine% )DlgGetRange%:( aLine%, BYREFaLower%, BYREF anUpper%)lower& = DlgGetRangeLongLower&:( aLine% )upper& = DlgGetRangeLongUpper&:( aLine% )DlgGetRangeLong%:( aLine%, BYREFaLower&, BYREF anUpper&)float = DlgGetFloat:( aLine% )choice% = DlgGetChoice%:( aLine% )choice$ = DlgGetChoiceString$:( aLine% )radio% = DlgGetRadio%:( aLine% )check% = DlgGetCheckBox%:( aLine% )combo$ = DlgGetComboBox$:( aLine% )time& = DlgGetTime&:( aLine% )date& = DlgGetDate&:( aLine% )text$ = DlgGetText$:( aLine% )file$ = DlgGetFile$:( aLine% )size& = DlgGetBufferSize&:( aLine% )DlgGetBuffer%:( aLine%, aBufAddr&, aMaxLen&)This collection of functions is available from callback routines to determine the current values of controls in the dialog. In all cases, aLine% is the line-number (or Control ID) of the entry whose value you want.Most are self-explanatory; the function is of the appropriate type to return the control's current value. A few, however, deserve a special note:When enquiring on a range (normal or long) there are three variants: the "Lower" and "Upper" two return the appropriate individual value; the third takes references to two variables of the appropriate type and sets both the upper and lower ends of the range in one call.The current setting of a choice-list can be obtained either as an integer index into the list of choices (DlgGetChoice%:), or as the string itself (DlgGetChoiceString$:).Only one function (DlgGetText$:) is needed to return the current value of a text editor, irrespective of the type of string (single, array or addres + length) that was used to create the control.When retrieving the contents of a text-buffer editor, DlgGetBufferSize&: can be used to get the length first before passing in the address of a suitably-sized buffer to DlgGetBuffer%:.See the corresponding DlgSetXXX%: functions for how to change the current value of a control from a callback function.C d"'h dh " d 'h dh  d'h dh 'h dh 'h dh w d""""G"j"""""" ""6""a"""" "V"A d" d'h dh /8 d8P"" "%"LUsage:DlgGroupStart%:DlgGroupEnd%:DlgActivateInGroup%:( aLine%)These commands new to AldurDlg allow the OPL programmer to construct dynamic dialogs, where a single line in the dialog can display one of a number of alternative controls (example below).The basic idea is that all dialog lines between DlgGroupStart%: and DlgGroupEnd%: are overlaid on top of one another, and only one is made visible at a time (using DlgActivateInGroup%:). Which control is made visible would normally depend on the setting of another control in the dialog.ExampleThe following basic example creates a dynamic search dialog where the type of data to search for controls the type of field used to enter the search data:proc Search%: Global idGroup% local type% local searchInt%, searchStr$(255), searchDate& DlgInit&:( "Search for", 0 ) DlgOnStateChange%:( "dcbSearchState" ) DlgChoiceListZero%:( type%, "Type", 0,0, "Number,Text,Date" ) DlgEnableStateChange%: idGroup% = DlgGroupStart%: DlgEditInt%:( searchInt%, "Number to find", 0, 1000 ) DlgEditText%:( Addr(searchStr$), "Text to find", 20 ) DlgEditDate%:( searchDate&, "Date to find", 0, KMaxDate& ) DlgGroupEnd%: DlgActivateInGroup%:( idGroup% ) if DlgExecute&: = 0 : return KFalse% : endif if type% = 0 return SearchForInt%:( searchInt% ) elseif type% = 1 return SearchForString%:( searchStr$ ) elseif type% = 2 return SearchForDate%:( searchDate& ) endifendpproc dcbSearchState%:( aLine% ) DlgActivateInGroup%:( idGroup% + DlgGetChoice%:( aLine% ) )endpFor full details of the functions used, see their entries in this help file, but some basic notes:There are three overlaid controls defined between DlgGroupStart%: and DlgGroupEnd%:; one each of a numerical, text and date editor.The Control ID (=line-number) of the first control (returned by DlgGroupStart%:) is saved in the global variable idGroup% for use in the callback routine.The setting of the choice-list determines which of the three controls will be visible. It is made zero-based to help the callback function. To enable the program to respond as this is changed you need to use both:DlgOnStateChange%: to name the callback function for this dialog. On its own, this function will not trigger state-change callbacks.DlgEnableStateChange%: to trigger state-change calls for the previous dialog control (this is to prevent excessive calls when only some controls need to be monitored).The callback function (dcbSearchState%:) is called whenever any monitored dialog control changes state. The parameter is the Control ID (=line-number) of the particular control that has changed. Here:There is only one monitored control so we don't need to check which it is. In a more complicated example, you would have saved the choice-list's ID in a global variable and checked aLine% against it and the other monitored controls.The DlgGetChoice%: function gets the current value of the choice-list selector; because we made it zero-based we can just add it to the ID of the start of the group and use DlgActivateInGroup%: to change the active control.Before we execute the dialog (but after all relevant controls have been defined) we must use DlgActivateInGroup%: to select the initial control. If you don't, they will all be visible on top of each other!mGh dh" d"'h dh " dD'h dh  d! d d9c'h dh 'h dh ' d ' d 'h dh ' d ' d 'h dh 0"=""")""i"0""" "S""i"""2""" "1"@""""""""P""!""""""""."""""""""6""^"@Usage:DlgOnFocusLoss%:( lossProcName$ )DlgOnFocusGain%:( gainProcName$ )Part of AldurDlg's callback handling, allowing truely responsive dialogs.lossProcName$ specifies the name of a user-written OPL procedure that will be called when the user tries to leave the current control of the dialog (i.e. when it is about to lose focus).If the named routine returns KTrue% (actually, any non-zero value), then the focus will not change, and the user will be forced to stay on the current line of the dialog.If the routine returns KFalse% (=zero), then the focus moves as the user intended and the next (or previous) line of the dialog becomes active.gainProcName$ specifies the name of a user-written OPL procedure that will be called when a control in the dialog gains focus.The return value of the named routine is ignored by the time the OnFocusGain callback is issued, the transition has already happened; the callback is merely to let you react to the fact.DlgOnFocusLoss%: can be useful for line-level validation; see also DlgOnValidate%: which can trigger dialog-level validation. One of the ZXZ Tips & Tricks entries (search for "T&T") discusses when you should use each.Note: Because the dialog hasn't finished executing, you CANNOT use the variables from the DlgEdit...%: routines, even if they were Global at the time of the callback, it is not known whether the dialog is going to be "accepted" or "cancelled", and so their values will NOT have been updated.Instead, you must use AldurDlg routines to access the current values of necessary controls see DlgGetInt%: and associated functions for more details.As well as being used to validate the sett=ing of a control, this callback can also be used to make the dialog react to changes in a similar manner to the DlgOnStateChange%: callback. One of the Tips & Tricks entries (search for "T&T") discusses when you should use each.Note: Partly for historical reasons, a focus-loss callback isn't normally generated when the user tries to dismiss the dialog; nor is a focus-gain callback generated as the dialog is first shown. Both of these behaviours can be altered using DlgCallbackOptions&:.Callback RoutineThe callback routines should be declared as:proc OnFocusLoss%:( aLine%, aDirection%)... if notOK% return KTrue% endif return KFalse%endpproc OnFocusGain%:( aLine%, aDirection% )...endpThe actual name of the procedures can be anything you want, as can the names of the two parameters; what matters is the procedures' return type ("%") and that there are two parameters of the correct type:aLine% gives the control ID (=line-number) of the control the user is trying to move away from (for focus-loss) or has just moved to (for focus-gain).aDirection% will be positive if the user is trying to move down to the next line (or has just done so), or negative if moving up to the previous one. Note that moving down from the last line, or up from the top line will wrap-around.If enabled with DlgCallbackOptions&:, aDirection% will be zero for a focus-gain callback as the dialog is dislayed or for a focus-loss callback as it is being dismissed. A focus-gain callback with aDirection% of zero can also be enabled after a focus-loss has prevented the user from leaving the field.If the callback's purpose is to validate individual controls, then most of the time you won't need to worry about the direction.ExampleA simple dialog where the user must enter one odd and one even number:proc OddEven%: local odd%, even% DlgInit&:( "Odd and even", 0 ) DlgOnFocusLoss%:( "dcbOddEvenFocus" ) DlgEditInt%:( odd%, "Odd number", 1, 99 ) DlgEditInt%:( even%, "Even number", 2, 100 ) if DlgExecute&: print "Odd="; odd%, "Even="; even% endifendpproc dcbOddEvenFocus%:( aLine%, aDir% ) local val% val% = DlgGetInt%:( aLine% ) if aLine% = 1 if (val% AND 1) = 0 giPrint "Number must be odd" return KTrue% endif else REM aLine% is 2 if (val% AND 1) = 1 giPrint "Number must be even" return KTrue% endif endifendpJ'h dh " d" d"h dh" dK'h dh J d d'h dh 'h dh  d d&0 d  d d 0 d- d'h dh 'h dh 0'h dh O d'N"D"""""/" """""""r" "r""3""<" """'""2""" """"""""C" ","""M""'""" """'""""" ""8""""T""$""";"""""" "" "_""G"$FUsage:DlgOnLoad%:( procName$ )Part of AldurDlg's callback handling, allowing truely responsive dialogs.procName$ specifies the name of a user-written OPL procedure that will be called just before the dialog is ready to be displayed.There are a number of uses for an on-load callback:Present a "guidance" screen to tell the user what to do;Cancel a "busy" message that might have been used while preparing the dialog for display;Initialise the state of controls. For the more complex reactive/dynamic dialogs, it is often easier to use common code, called both from an on-load callback and the various state-change/focus-loss callbacks;Clear or initialise some "space-reserving" value used for a dynamic DlgText%: or DlgAnnotate%: line.Callback RoutineThe callback routine should be declared as:proc OnLoad%:...endpThe actual name of the procedure can be anything you want; what matters is the procedure's return type ("%") and that it has no parameters.ExampleA simple "what to do" dialog is shown as the dialog is opened.proc OnLoadExample: local first$(20), last$(20), telephone$(20) DlgInit&:( "Enter new contact", 0 ) DlgOnLoad%:( "dcbContactLoad" ) DlgEditText%:( Addr(first$), "First name", 0 ) DlgEditText%:( Addr(last$), "Last name", 0 ) DlgEditText%:( Addr(telephone$), "Telephone no.", 0 ) if DlgExecute&: SaveContact: endifendpproc dcbContactLoad%: dInit "", KDlgNoTitle% dPosition 0, -1 dText "", "Enter the details of the new contact," dText "", "including the full area code in their" dText "", "telephone." DialogendpC d"'h dh " d"h dh" d 'h dh J d d49Ze'h dh , dG d""""""/" "y"D" "" "" ""}""?"TUsage:DlgOnStateChange%:( procName$ )DlgEnableStateChange%:Part of AldurDlg's callback handling, allowing truely responsive dialogs.procName$ specifies the name of a user-written OPL procedure that will be called when the state (i.e. current value) of selected controls changes. Because a program rarely needs to know about every state-change of every control, DlgEnableStateChange%: must be used after defining any control for which you want to receive feedback.The callback is typically used to change the values or states of other controls as the monitored line changes (see examples). Unlike other callback routines, the return value has no effect on the dialog's behaviour and is ignored.Note: Because the dialog hasn't finished executing, you CANNOT use the variables from the DlgEdit...%: routines, even if they were Global at the time of the callback, it is not known whether the dialog is going to be "accepted" or "cancelled", and so their values will NOT have been updated.Instead, you must use AldurDlg routines to access the current values of necessary controls see DlgGetInt%: and associated functions for more details.Note: Be careful if reacting to changes in a numeric editor; although you will receive callbacks as the user is typing, you may confuse of frustrate the user if too much happens for intermediate values (e.g. for "1" and "12" on the way to typing "123").Note: Under EPOC, it is often possible to enter invalid values for numeric editors (e.g. characters into a float editor; an invalid date in a date editor). Normally this is OK, since the user will not be allowed to move away from that line, nor accept the dialog, until a valid value has been entered.If a DlgOnStateChange%: callback has been enabled for such fields, and the currently-entered value is invalid, then a callback will NOT be made: this avoids the problem of trying to indicate invalid values in DlgGetInt%: etc., as well as assorted internal problems.Instead of making the callback, AldurDlg will normally show the Info Message that would appear if you tried to leave the line. You can (mostly) disable this message using DlgCallbackOptions&:.On the whole, OnStateChange events are probably best suited to "discrete" controls e.g. reacting to changes in a choice-list, radio-buttons or a check-box, rather than attached to numeric editors.Callback RoutineThe callback routine should be declared as:proc OnStateChange%:( aLine%)...REM update values or states of other controls...endpThe actual name of the procedure can be anything you want, as can the name of the parameter; what matters is the procedure's return type ("%") and that there is one parameter of the correct type:aLine% gives the control ID (=line-number) of the control whose state (i.e. value) has changed.ExampleSee the example under DlgGroupStart%: for how DlgOnStateChange%: can be used with overlaid controls for one type of dynamic dialog.Below is another example showing how controls can be turned on or off as other controls are altered:proc Dialing: local areaCode$(5), dialPrefix$(5), usePrefix% local modemType%, initString$(10) global idUsePrefix%, idType% DlgInit&:( "Dialing & modem properties", 0 ) DlgOnStateChange%:( "dcbDialingState" ) DlgEditText%:( Addr(areaCode$), "Area code", 0 ) idUsePrefix% = DlgCheckBox%:( usePrefix%, "Use prefix?" ) DlgEnableStateChange%: DlgEditText%:( Addr(dialPrefix$), " Dial prefix", 0 ) dcbDialingState%:( idUsePrefix% ) idType% = DlgChoiceList%:( modemType%, "Modem type", 0,0, "Pace,Multitech,Other" ) DlgEnableStateChange%: DlgEditText%:( Addr(initString$), "Init. string", 0 ) dcbDialingState%:( idType% ) if DlgExecute&: print "Area code = "; areaCode$ if usePrefix% print "Dial pefix = "; dialPrefix$ else print "No dial prefix" endif print "Initialise string: "; initString$ endifendpproc dcbDialingState%:( aLine% ) local modem% if aLine% = idUsePrefix% DlgSetWholeVisibleLine%:( aLine% + 1, DlgGetCheckBox%:( aLine% ) ) else modem% = DlgGetChoice%:( aLine% ) if modem% = 1 DlgSetText%:( aLine% + 1, "AT&F &K4" ) elseif modem% = 2 DlgSetText%:( aLine% + 1, "AT&F &E5" ) endif DlgSetDimmedLine%:( aLine% + 1, modem% < 3 ) endifendpNotes:You must remember to use DlgEnableStateChange%: after any dialog-line for which you wish to receive callbacks.The callback uses DlgSetWholeVisibleLine%: to show or hide the "Dialing prefix" entry, depending on the state of the check-box.When a "known" modem-type is chosen, the callback-function prefills the "Init. string" line and uses DlgSetDimmedLine%: to inactivate it. For the "Other" modem-type, the user is allowed to enter their own string.Rather than repeating the logic for setting the initial state of the dialog lines, the main procedure calls the callback twice (once for each controlling line). In effect, it "pretends" that the state has just changed.Global variables are used to hold the Control IDs (=line-numbers) of the two lines being monitored; there's no need to use them for the lines being adjusted, since these are always the next line ("aLine% + 1").I d" d"h dh"'h dh " d>'h dh J dM d&0 d  d0 d/0 d  d d d,Z d`'h dh  deo'h dh 'h dh 'h dh E"7"""""/" "o""f""Q""2""" """"""""C" ","""")"""m""J" "." """""" "" ""7""z""Z"""" ""D"""@"""V"e""_"@Usage:DlgOnValidate%:( procName$ )Part of AldurDlg's callback handling, allowing truely responsive dialogs.procName$ specifies the name of a user-written OPL procedure that will be called when the user tries to "action" the dialog. If KADlgTrapEscape% (=$4000) was included in DlgInit&:'s flags% parameter, it is also called when they try to dismiss the dialog (with ESC or whatever is the "cancel" key).If the named routine returns KTrue% (actually, any non-zero value), then the dialog is not closed and the user must continue interacting with it.If the routine returns KFalse% (=zero), then the dialog is closed as normal, and control returns to the DlgExecute&: statement.As the name implies, DlgOnValidate%: is useful for validating all the data that the user has entered to ensure it is correct (see also DlgOnFocusLoss%: which can trigger line-level validation). See Validating Data (search for "ValidatingData") for tips on when you should use each.The validation routine can also call DlgSetRetCode8%: to change the value that gets passed back from DlgExecute&: after the dialog closes. This can be any 32-bit ("&"-type) number you wish.It can also call DlgDismissDialog%: this effectively makes the dialog act as though the CANCEL key (usually ESC) was pressed; the OPL variables referenced by the dialog would not be updated.Note: Because the dialog hasn't finished executing, you CANNOT use the variables from the DlgEdit...%: routines, even if they were Global. At the time of the callback, it is not known whether the dialog is going to be "accepted" or "cancelled", and so their values will NOT have been updated.Instead, you must use AldurDlg routines to access the current values of necessary controls see DlgGetInt%: and associated functions for more details.Callback RoutineThe callback routine should be declared as:proc OnValidate%:( aLine%, aKey&)... if notOK% return KTrue% endif return KFalse%endpThe actual name of the procedure can be anything you want, as can the names of the two parameters; what matters is the procedure's return type ("%") and that there are two parameters of the correct type:aLine% holds the control ID (=line-number) of the active control when the user pressed ENTER (or tapped one of the buttons or pressed its hotkey).aKey& holds the key that was pressed to trigger the call (or the associated hotkey if a button was tapped). This is the same value as would be returned by DlgExecute&: if callbacks weren't in use.Much of the time your validation code will ignore the aLine% parameter, since it generally doesn't matter which line the user was on when they pressed ENTER (or pressed a button). However, there are times when it can be useful.Often, you don't even need to examine aKey& if there are no buttons, or only accept/cancel buttons (remember, the "cancel" button doesn't normally cause the OnValidate-callback to be called).If appropriate to the validation checks, you can use DlgSetFocus%: to change the active line of the dialog to the one that has been found to be in error.ExampleA simple example shows how validation can be used to impose conditions that cannot be achieved with just the min/max settings:proc Triangle: local angle1%, angle2%, angle3% DlgInit&:( "Enter angles of a triangle", 0 ) DlgOnValidate%:( "dcbTriangleValidate" ) DlgEditInt%:( angle1%, "1st angle", 1, 180 ) DlgEditInt%:( angle2%, "2nd angle", 1, 180 ) DlgEditInt%:( angle3%, "3rd angle", 1, 180 ) if DlgExecute&: print "Angles are:", angle1%, angle2%, angle3% endifendpproc dcbTriangleValidate%:( aLine%, aKey& ) local a%, b%, c% a% = DlgGetInt%:( 1 ) b% = DlgGetInt%:( 2 ) c% = DlgGetInt%:( 3 ) if a% + b% + c% <> 180 giPrint "Angles must add up to 180" return KTrue% endifendpNotes:For simplicity, I have hard-coded the line-numbers (or Control IDs) of the three integer editors into the three DlgGetInt%: calls. In practice, for anything other than very simple cases, I strongly recommend using global variables to hold the Control IDs/line-numbers and refering to these in the callback, e.g.:...global idA%...idA% = DlgEditInt%:( ... )...a% = DlgGetInt%:( idA% )...If you ever go back and rearrange a dialog (e.g. adding a DlgText%: line above the three editors to better explain how to use the dialog), the use of variables to hold the IDs will save a lot of confusion.I tend to name callback functions with three components:"dcb" for "dialog call back"a short name referring to the dialog's use ("Triangle" in this case)the type of callback (e.g. "Validate").To avoid confusing the end-user, it's polite to tell them why you've just stopped them accepting the dialog.To achieve the same effect without using callbacks, Triangle: would need to look something like:proc Triangle: local angle1%, angle2%, angle3% while KTrue% DlgInit&:(...) ... if DlgExecute&: = 0 break endif if angle1% + angle2% + angle3% = 180 print "Angles are:", angle1%, angle2%, angle3% break endif endwhendpapart from being more complicated (the extra while..endwh loop), it has the disadvantage of redisplaying the dialog whenever the angles don't add up correctly.An alternative from of the validate routine could be:proc dcbTriangleValidate%:( aLine%, aKey& ) local a%, b%, c% a% = DlgGetInt%:( 1 ) b% = DlgGetInt%:( 2 ) c% = DlgGetInt%:( 3 ) if a% + b% + c% <> 180 dInit "Error" dText "", "Angles must add up to 180" dButtons "Forget it", -27, "Try again", 13 if Dialog return KTrue% else DlgDismissDialog%: endif endifendpIf the angles don't add up, this shows a normal OPL dialog allowing the user to:"Try again": the validate routine returns KTrue% so that the original dialog remains on screen to accept corrections; or"Forget it": the validate routine calls DlgDismissDialog%: to turn the "accept" key that called it into a "cancel" key the original dialog is closed and the main procedure's variables (angle1%, etc.) are not updated.As shown here, a validation routine (or any AldurDlg callback) can display additional dialogs, using either OPL commands or more AldurDlg routines. In the latter case, the new dialogs can have their own callbacks, leading to as many levels of dialogs as you want (or can cope with!). See the main AldurDlgDemo program for more examples.Dialog-Centered ProgrammingThe previous example shows how error-checking loops can be eliminated by using validation callbacks. Amongst other uses, DlgOnValidate%: allows you to write what might be termed "dialog-centric" programs.Imagine you were using a dialog to decide what should happen next and what parameters to use, and want to allow this to be peformed many times in a row until the user quits. An outline example without callbacks:proc DoThings: local dlg% ... while KTrue% DlgInit&:( "Choose what/how...", 0 ) ... dlg% = DlgExecute&: if dlg% = 0 break endif ... REM decide what to do, which parameters to use... ... endwhendpCould be turned into something like:proc DoThings: DlgInit&:( "Choose what/how...", 0 ) DlgOnValidate%:( "dcbDoThings" ) ... DlgExecute&:endpproc dcbDoThings%:( aLine%, aKey& ) ... REM using DlgGetXXX: functions, decide  REM what to do, which parameters to use... ...endpThis approach isn't always right by keeping the dialog on screen you won't be able to see what's underneath but in many cases, firing commands from a dialog box is handy.ExampleA slightly artificial example, using selectable text-lines (dText of old) shows how this technique might be used:proc PerformActions: local disk% DlgInit&:( "Select disk operation", 0 ) DlgOnValidate%:( "dcbDiskValidate" ) DlgChoiceList%:( disk%, "Disk to use", 0,0, "C:,D:,Z:" ) DlgText%:( "Format", "Format selected disk", KDTextAllowSelection% ) DlgText%:( "Backup", "Backup selected disk", KDTextAllowSelection% ) DlgText%:( "Restore", "Restore selected disk", KDTextAllowSelection% ) DlgExecute&:endpproc dcbDiskValidate%:( aLine%, aKey& ) local disk% disk% = DlgGetChoice%:( 1 ) if aLine% = 1 giPrint "Select operation and press RETURN" elseif aLine% = 2 FormatDisk:( disk% ) elseif aLine% = 3 BackupDisk:( disk% ) elseif aLine% = 4 RestoreDisk:( disk% ) endif return KTrue%endpNotes:The OnValidate routine always return KTrue% because we don't want to dismiss the dialog and its command options until the user press ESC (which won't be seen by the callback).If the user leaves the disk-selector active, they are told to pick one of the commands and try again.When any of the three "command lines" are selected, the corresponding procedure is called. Any feedback from these would generally be through another dialog box (since the underlying screen is obscured by the main dialog box).Again for simplicity, I've hard-coded the line-numbers of the controls; for robustness, global variables would probably be used (perhaps one for the disk selector, and one for the first command line).FP d" d"h dh" d"'h dh "' d " d6$'h dh J d+ d'h dh 'h dh  d d d&0 d  d,^ d'h dh 'h dh  d d d?;'h dh Ph dh9E(mah dh6OQy' d ' d Sh dh d%z d'h dh fr""""""/" "x""" """n"""4""8"""J" " """c""0""E"%""0" "N""""" ""2""" """"""""C" "," ""7""""""" ""6"""5" "X"""7" "." "":" ""-" "g"*""I"("""" ",""M""" ""z""E""<""1"" """"CUsage:oldPos% = DlgPosition%:( xPos%, yPos% )Allows the initial position of the dialog to be controlled (as dPosition); also allows the position to be changed during a callback.OPL AldurDlgdPosition x%, y% DlgPosition%:( x%, y% )AldurDlg++As well as setting the initial position, AldurDlg will allow you to move the dialog during a callback.Can be called between DlgInit&: and DlgExecute&: to set the initial position of the dialog when it opens. Can also be called during a callback routine to change the current position of the dialog.In both cases, the return value of the call indicates the previous position in the following manner:oldPos% = -1Dialog was not aligned in one of the nine "standard" positions (this is reserved for future use, should I allow arbitary placement of dialogs).oldPos% AND $0F=0 Left edge of screen=1 Middle of screen=2 Right edge of screenoldPos% AND $F0=$00 Top edge of screen=$10 Middle of screen=$20 Bottom edge of screen`D d" d" d /'h dh  d'h dh ,'h dh  g'h dh  de0 dV0 dY0 d"("?" "=""" """")""6"" "" """""O""R"CUsage:DlgRadioButton%:( BYREF aButton%, aPrompt$, aFlags&, aWidth%, aButtonList$ )DlgRadioButtonZero%:( BYREF aButton%, aPrompt$, aFlags&, aWidth%, aButtonList$ )See also: DlgChoiceListItem%: DlgSetChoiceSeparator%: DlgComboBox%:New to AldurDlg, these routines define a set of radio-buttons in a dialog.They are used in the same way as the routines for choice-lists: DlgRadioButton%: will define the line in the dialog; the list of button names are built up from its aButtonList$ parameter, and/or those of DlgRadioButtonItem%: (an alternate name for DlgChoiceistItem%:). As with DlgChoiceList%:, the DlgRadioButtonZero%: version operates the same, but choices are numbered from zero instead of one.flags%?ZXZwidth%?ZXZNote: DlgChoiceListItem%: and DlgRadioButtonItem%: are different names for the same routine the list that is built is used for either choice-lists (DlgChoiceList%:), radio buttons (DlgRadioButton%:) or combo boxes (DlgComboBox%:).C d" d'h dh D8 d8K d d  0 d "" ":"""<"@""T" """"" """"O""""d""""" ""@ d,'h dh F8 d8h d"%" "<"""B"A d" dX'h dh 8 d8L"Q" ""zGUsage:oldSep% = DlgSetChoiceSeparator%:( newSep% )This function new to AldurDlg changes the separator-character used when building lists for choice-lists, radio buttons and combo-boxes. newSep% should be the ASCII code for the new separator; the old separator character is returned, so that you can restore the original situation later.If zero is used for the separator, then no separator is used; the whole of any string given in a DlgChoiceListItem%: call is added to the list of choices.The OPX actually maintains two copies of this setting:A default setting that is global to the whole program, andA current setting that is local to the current dialog.Whenever DlgInit&: is called, the newly-created dialog's current setting is copied from the global default setting.If DlgSetChoiceSeparator%: is called during dialog construction (i.e. between DlgInit&: and DlgExecute&:) or from a callback, then it will update the current dialog's separator (and return the current dialog's old separator).If DlgCallbackOptions&: is called at any other time, then it will update the global default separator (and return the old global separator).The initial default separator (and the only option under normal OPL) is the comma (","). The separator character can be changed as often as you like, even while building an item-list: it is the current value when DlgExecuteChoiceListItem%: is executed that matters, not when you call DlgExecute&:.ExampleThe following calls:...DlgChoiceListItem%:( "Buckingham Palace,House of Lords" )DlgSetChoiceSeparator%:( %: ) REM uses colonDlgChoiceListItem%:( "23, Railway Cuttings:52, Festive Road" )...Will add the following four items to the list being built:Buckingham PalaceHouse of Lords23, Railway Cuttings52, Festive RoadIn practice, I tend to find DlgSetChoiceSeparator%:( 0 ) the most useful, and just call DlgChoiceListItem%: once for each entry.F d"h dh" d4'h dh $ d d7;'h dh 7'h dh t d d  d+ d d;G d1"-"""n"""a""'"""2"""." " "'""#"" """4" "" ".""E"""=""2"""-" """""" """BUsage:DlgSetDimmed%:( trueOrFalse% )DlgSetDimmedLine%:( aLine%, trueOrFalse% )trueOrFalse% = DlgIsDimmed%:( aLine% )These functions new to AldurDlg allow a line in a dialog to be dimmed the user will skip over it as they move and will not be able to alter its content.The frist version is for use during construction, and affects the last dialog line that was defined; the second version is primarily for use in callbacks and the line-number (or Control ID) must be specified. Finally there is a query function to determine the current state of the specified line.Note: These functions cannot be used with dialog buttons (but see DlgSetDimmedButton%:).A d" dx'h dh  d*Y0 d "q""""""V""S"CUsage:DlgSetDimmedButton%:( aButtonID%, trueOrFalse% )trueOrFalse% = DlgIsDimmedButton%:( aButtonID%)These functions new to AldurDlg allow a dialog button to be dimmed, and its current state to be checked. When dimmed, a button will be inactive, and cannot be "pressed".The aButtonId% parameter is basically the same as that used for aHotKey% in the call to DlgButton%:, but with the following provisos:For any "cancel" key designed to dismiss the dialog (i.e. one whose value aHotKey% was negative) you should use KBidCancel% for the button ID.For letter-based hot-keys, use the letter concerned but omit any modifiers that were used when creating the button (e.g. to hide the key-label or to not need CTRL). Ensure you use the same case as when the button was defined.For non-letter-based hotkeys, you should use the following values (defined in AldurDlg.oxh):-1 KBidEscape%-2 KBidOK%-3 KBidTab%-4 KBidDelete%-5 KBidSpace%C0 d" d" d i'h dh  d d'h dh 'h dh ]'h dh   "b""""" "2""" "#"J""" ""4"""N" ""@BUsage:DlgSetFocus%:( aLine% )See also: DlgGetFocus%:Sets which line has the focus in the dialog. It can be used before DlgExecute&: to set the initial line when the dialog opens, or from a callback to reposition the focus (e.g. to a line that fails validation).Note: If called during construction, the selected line must already have been defined (so it's best to call it just before DlgExecute&:).Note: The first line within the dialog is always number 1, whether or not there's a title bar. Divider-lines between controls are never counted as distinct line-numbers.)B d'h dh 8 d8 d0 d0 d "" ""D" """u" """"nAUsage:DlgSetRetCode%:( aRetCode% )Called from within a DlgOnValidate%: callback, this routine sets the return code that will be returned by DlgExecute&: back to the main OPL program. The value will be ignored if the DlgOnValidate%: routine returns KTrue% (i.e., if the dialog should not be closed).Note: Should only be called during a DlgOnValidate%: callback. B d$'h dh   d ?0 d""""F" "A""""-"""" " BUsage:DlgSetTitle%:( aTitle$ )Allows the text of a dialog's title-bar to be changed from a callback function.zxz! For some reason, getting the current title isn't supported yet.Note: At present, the dialog will not resize if the title-bar is changed; if you plan on altering the title-bar, make sure you reserve as much space as may be needed when you first create the dialog. You can then use a DlgOnLoad%: callback to set the correct initial value. The example for DlgSetTextLabel%: demonstrates this principle.A d" d 'h dh PES0 d """""" "="""BUsage:DlgSetVisible%:( trueOrFalse% )DlgSetVisibleLine%:( aLine%, trueOrFalse% )trueOrFalse% = DlgIsVisible%:( aLine% )These functions new to AldurDlg allow the value-part (right-hand side) of a line in a dialog to be made visible or hidden. The value of a hidden field will still be maintained (and can be changed by callbacks).The frist version is for use during construction, and affects the last dialog line that was defined; the second version is primarily for use in callbacks and the line-number (or Control ID) must be specified. Finally there is a query function to determine the current state of the specified line.Note: These functions cannot be used with dialog buttons (but see DlgSetDimmedButton%:).A d" d{'h dh  d*Y0 d "t"""K""""[""S"BUsage:DlgSetWholeVisible%:( trueOrFalse% )DlgSetWholeVisibleLine%:( aLine%, trueOrFalse% )trueOrFalse% = DlgIsWholeVisible%:( aLine% )These functions new to AldurDlg allow the whole of a line in a dialog to be made visible or hidden. The value of a hidden field will still be maintained (and can be changed by callbacks).The frist version is for use during construction, and affects the last dialog line that was defined; the second version is primarily for use in callbacks and the line-number (or Control ID) must be specified. Finally there is a query function to determine the current state of the specified line.Note: These functions cannot be used with dialog buttons (but see DlgSetDimmedButton%:).A d" d'h dh  d*Y0 d """"4""""[""S"GGUsage:DlgSetInt%:( aLine%, anInt% )DlgSetLong%:( aLine%, aLong& )DlgSetRangeLower%:( aLine%, aLower% )DlgSetRangeUpper%:( aLine%, anUpper% )DlgSetRange%:( aLine%, aLower%, anUpper%)DlgSetRangeLongLower%:( aLine%, aLower& )DlgSetRangeLongUpper%:( aLine%, anUpper& )DlgSetRangeLong%:( aLine%, aLower&, anUpper&)DlgSetFloat%:( aLine%, aFloat )DlgSetChoice%:( aLine%, aChoice% )DlgSetRadio%:( aLine%, aRadio% )DlgSetCheckBox%:( aLine%, aCheck% )DlgSetComboBox%:( aLine%, aCombo$ )DlgSetComboBoxFromList%:( aLine%, anIndex&)DlgSetTime%:( aLine%, aTime& )DlgSetDate%:( aLine%, aDate& )DlgSetText%:( aLine%, aText$ )DlgSetFile%:( aLine% )DlgSetBuffer%:( aLine%, aBufAddr& )This collection of functions is available from callback routines to change the current values of controls in the dialog. In all cases, aLine% is the line-number (or Control ID) of the entry whose value you want to update.Most are self-explanatory; the function accepts a parameter (or parameters) of the appropriate type to update the control's current value. A few, however, deserve a special note:The upper and lower values of ranges can be set together or individually.Only the current selection of a choice-list can be changed here; to alter the contents of a choice-list, see DlgAppendChoiceList%: and DlgReplaceChoiceList%:.Presently, only one function (DlgSetText$:) is provided to alter the current value of a text editor; the array and buffer + length options available when creating the control are not provided.The contents of a combo-box's text-editor can be set from a string (DlgSetComboBox%:) or from one of the elements in the associated choice-list (DlgSetComboBoxFromList%:). This function can also be used during construction.See the corresponding DlgGetXXX%: functions for how to obtain the current value of a control from a callback function.C d"'h dh " d 'h dh  dJ'h dh 'h dh 'h dh w d""""Q"m"""""" ""D""=""8"" "V"@Usage:DlgText%:( aPrompt$, aText$, aFlags%)DlgAnnotate%:( aPrompt$, aText$, aFlags%)Reproduce the function of OPL's dText command, as well as offering a smaller-font version useful for annotating the function of other controls (use of this can be seen extensively in the Control Panel's "Dialing" component).OPL AldurDlgdText aPrompt$, aText$ DlgText%:( aPrompt$, aText$, 0 )dText aPrompt$, aText$, flags% DlgText%:( aPrompt$, aText$, flags% )dText "", "", KDTextSeparator% DlgDividerAfter%:AldurDlg++Unlike OPL, both aPrompt$ and aBody$ can be empty strings (resulting in a blank line).DlgAnnotate%: allows text to be shown in a smaller font; useful for annotating the meaning of other controls (you can see an example of this from the "Modems" option of the Psion's Control Panel). Otherwise, it behaves identically to DlgText%:.AldurDlg--AldurDlg does not support the KDTextSeparator% option (=$800) to produce a line between two other controls. Instead, use the function DlgDividerAfter%: which will do the same job (it can be used after any other control).However, the KDTextLineBelow% option (=$200) can still be used to draw a line below the text-line being defined.Under AldurDlg, divider lines, however created, never affect line-numbering see the notes below.As with OPL's dText command, the following flags% can be used to align aText$ if aPrompt$ is empty (defined in Const.oph):0 KDTextLeft%1 KDTextRight%2 KDTextCenter%The following can also be used (whether or not aPrompt$ is empty) to alter the appearance:$100 KDTextBold% (not in EPOC32)$200 KDTextLineBelow%$400 KDTextAllowSelection%and operate as for OPL's dText command. As noted above, the following flag option is not supported (but see DlgDividerAfter%:):$800 KDTextSeparator%Note: Unlike OPL, a dividing line created through either KDTextSeparator% or KDTextLineBelow% will not affect the line-numbering of subsequent controls. For example, with OPL, the following snippet:dInit "Test"dText "", "Select an option", KDTextLineBelow%dText "1", "Option one", KDTextAllowSelection%dText "2", "Option two", KDTextAllowSelection%opt% = Dialogwill return either "3" or "4" (the title counts as line one; the "Select an option" is line two). However, the following:dInit "Test"dText "", "Select an option"dText "", "", KDTextSeparator%dText "1", "Option one", KDTextAllowSelection%dText "2", "Option two", KDTextAllowSelection%opt% = Dialogproduces exactly the same display but returns "4" or "5" because the standalone separator line counts as a line in the dialog. However, the two equivalent snippets using AldurDlg:DlgInit&:( "Test", 0 )DlgText%:( "", "Select an option", KDTextLineBelow% )DlgText%:( "1", "Option one", KDTextAllowSelection% )DlgText%:( "2", "Option two", KDTextAllowSelection% )opt% = DlgExecute&:and:DlgInit&:( "Test", 0 )DlgText%:( "", "Select an option", 0 )DlgDividerAfter%:DlgText%:( "1", "Option one", KDTextAllowSelection% )DlgText%:( "2", "Option two", KDTextAllowSelection% )opt% = DlgExecute&:will both return "2" or "3" (the title line never counts as a line; "Select an option" is always line one; neither method of specifying the divider line counts as a line on its own).I d"0 d"8 d8" dY'h dh  d d'h dh  W'h dh 'h dh  'h dh q'h dh c'h dh { d [ d! d0 d{8 d8D"R" """ """" """?""D"""""""3" "" """"" ""Y""F" ""T"""U"""""""""" ""/""$"""O""""3""""k""""K!  a%y=AldurDlg OPX v1.13R d" r AldurDlgOpx! Contact MeR d "bA AldurDlgOpx!*Graham Holden Author website email contact LicenceR  d "   AldurDlgOpx! DeploymentR d "  AldurDlgOpx! RevisionsR  d "Version 1.13, February 2006First public release. Includes several improvements over a previous private release; primarily better handling of state-changes in numerical editors (for both typing values and using the pointer).m0 d" d AldurDlgOpx!How to Get HelpR d" 7  AldurDlgOpx!OPL AldurDlgR d"& AldurDlgOpx! String VariablesR d"  AldurDlgOpx!kdFile DlgFile%: dText DlgEditText%: DlgEditTextMax%: DlgEditTextArray%: DlgComboBox%: DlgChoiceListString%: Callback RoutinesR d" AldurDlgOpx!`callbacks eventsDlgOnLoad%:DlgOnFocusLoss%:DlgOnFocusGain%:DlgOnStateChange%DlgOnValidate%: Control IDsR d"0. AldurDlgOpx!Vcallbacks events line numbers line-numbers Control IDs Control-IDs DlgGet DlgSet DlgIs Dynamic ControlsR d"Q! AldurDlgOpx!Bcallbacks eventsDlgGroupStart%:DlgGroupEnd%DlgActivateInGroup%: Reactive ControlsR d" AldurDlgOpx!Vcallbacks events line numbers line-numbers Control IDs Control-IDs DlgGet DlgSet DlgIs Validating DataR d"t  AldurDlgOpx!wcallbacks events line numbers line-numbers Control IDs Control-IDs DlgGet DlgSet DlgIs DlgOnValidate%: DlgOnFocusLoss%: Tips and TricksR d"> AldurDlgOpx!' AldurDlg.oxhR  d " AldurDlgOpx! DlgInit&:R  d "+  AldurDlgOpx!dInit DlgExecute&:P6?Y AQ DlgExecute&:R  d ""m#y AldurDlgOpx!3Dialog DlgInit&: DlgSetRetCode%: DlgDismissDialog%:DlgActivateInGroup%:R d"Usage:DlgActivateInGroup%:( aLine%)See also: DlgGroupStart%: DlgGroupEnd%Activates a selected control from a group of overlaid controls; all others become inactive.$ AldurDlgOpx!+OnStateChange DlgGroupStart%: DlgGroupEnd%:DlgAddTrailer%:R d"%&Q AldurDlgOpx! DlgAnnotate%:R d "rUsage:DlgAnnotate%:( aPrompt$, aText$, aFlags%)See also: DlgText%:Similar to dText, but uses a smaller font.'Q AldurDlgOpx!dText*DlgAppendChoiceList:DlgReplaceChoiceList:R+ d*"( dH'h dh | d"A"""" AldurDlgOpx!dChoice DlgChoiceList DlgButton%:R  d ")L*e AldurDlgOpx!dButtonsDlgCallbackOptions&:R d"+ ,e AldurDlgOpx!YCallBack DlgOnValidate%: DlgOnStateChange%: DlgOnFocusLoss%: DlgOnFocusGain%: DlgOnLoad%: DlgCheckBox%:R d "Usage:DlgCheckBox%:( BYREF aCheck%, aPrompt$ )Creates a check-box in an identical manner to dCheck in OPL.OPL AldurDlgdCheck yesno%, aPrompt$ DlgCheck%:( yesNo%, aPrompt$ )- AldurDlgOpx! dCheckBoxSDlgChoiceList%:DlgChoiceListZero%:DlgChoiceListString%:DlgChoiceListStringZero%:RT dS". / AldurDlgOpx!xdChoice DlgChoiceListItem%: DlgRadioButtonItem%: DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListDlgChoiceListCount:R d"yUsage:count% = DlgChoiceListCount%:( aLine% )Returns the number of items in the choice-list of the specified control. d" d/'h dh I"(" AldurDlgOpx!dChoice DlgChoiceList(DlgChoiceListItem%:DlgRadioButtonItem%:R) d("01 AldurDlgOpx!xdChoice DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListStringZero%: DlgRadioButton%: DlgRadioButDlgChoiceListString%:R d"Usage:DlgChoiceString%:( aStrAddr&, aPrompt$, aFlags&, aWidth%, aChoiceList$ )See also: DlgChoiceList%:Creates a choice-list (like dChoice) but returns the selection as a string instead of an index.2Q AldurDlgOpx!xdChoice DlgChoiceListItem%: DlgRadioButtonItem%: DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListDlgChoiceListStringZero%:R d"3-4Q AldurDlgOpx!xdChoice DlgChoiceListItem%: DlgRadioButtonItem%: DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListDlgChoiceListZero%:R d"Usage:DlgChoiceListZero%:( BYREF aChoice%, aPrompt$, aFlags&, aWidth%, aChoiceList$ )See also: DlgChoiceList%:Creates a choice-list (like dChoice) but with elements numbered from zero (instead of one).5Q AldurDlgOpx!xdChoice DlgChoiceListItem%: DlgRadioButtonItem%: DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListPM?9))5Aui DlgComboBox%:R d "78 AldurDlgOpx!xdChoice DlgChoiceListItem%: DlgRadioButtonItem%: DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListDlgDismissDialog%:R d"9 : AldurDlgOpx!CallBackDlgDividerAfter%:R d";<' AldurDlgOpx!dTextDlgEditBuffer%:R d"=> AldurDlgOpx!xdEdit dEditMulti DlgEditText%: DlgEditTextArray%: DlgEditTextMax%: DlgEditTextEx%: DlgEditTextArrayEx%: DlgEditTextMaxEx]DlgEditDate%:DlgEditDateNoPop%:DlgEditTime%:DlgEditTimeAndDate%:DlgEditTimeAndDateNoPop%:R^ d]"?I @[ AldurDlgOpx!idDate dTime DlgEditDate%: DlgEditDateNoPop%: DlgEditTime%: DlgEditTimeAndDate%: DlgEditTimeAndDateNoPop%:DlgEditDateNoPop%:R d"Usage:DlgEditDateNoPop%:( BYREF aDate&, aPrompt$, aMin&, aMax& )See also: DlgEditDate%:Like dDate, but doesn't allow a pop-up calendar.AQ AldurDlgOpx!idDate dTime DlgEditDate%: DlgEditDateNoPop%: DlgEditTime%: DlgEditTimeAndDate%: DlgEditTimeAndDateNoPop%:DlgEditFloat%:DlgEditReal%:R d"BPC  AldurDlgOpx!:dFloat DlgGetReal: DlgSetReal%: DlgGetFloat: DlgSetFloat%:DlgEditInt%:DlgEditLong%:R d"DEk AldurDlgOpx!7dLong DlgGetLong%: DlgSetLong%: DlgGetInt%: DlgSetInt%: DlgEditLong%:R d "mUsage:DlgEditLong%:( BYREF aVar&, aPrompt$, aMin&, aMax& )See also: DlgEditInt%:The equivalent of dLong.FQ AldurDlgOpx!DdLong DlgEditInt%: DlgGetLong%: DlgSetLong%: DlgGetInt%: DlgSetInt%:!DlgEditRange%:DlgEditRangeLong%:R" d!"GH AldurDlgOpx!xDlgGetRange%: DlgGetRangeUpper%: DlgGetRangeLower%: DlgGetRangeLong%: DlgGetRangeLongUpper&: DlgGetRangeLongLower&: DlgSDlgEditRangeLong%:R d"Usage:DlgEditRangeLong%:( BYREF aLower&, aSep$, BYREF aUpper&, aPrompt$, aMin&, aMax& )See also: DlgEditRange%:Edits a pair of long ("&") variables.I AldurDlgOpx!xDlgEditRange%: DlgGetRange%: DlgGetRangeUpper%: DlgGetRangeLower%: DlgGetRangeLong%: DlgGetRangeLongUpper&: DlgGetRangeL DlgEditReal%:R d "Usage:DlgEditFloat%:( BYREF aFloat, aPrompt$, aMin, aMax )See also: DlgEditFloat%: (they are two names for the same function) d<'h dh D8 d8"5" ":" AldurDlgOpx!IdFloat DlgEditFloat%: DlgGetReal: DlgSetReal%: DlgGetFloat: DlgSetFloat%:1DlgEditText%:DlgEditTextArray%:DlgEditTextMax%:R2 d1"J K AldurDlgOpx!xdEdit dEditMulti DlgEditText%: DlgEditTextArray%: DlgEditTextMax%: DlgEditTextEx%: DlgEditTextArrayEx%: DlgEditTextMaxExDlgEditTextArray%:R d"Usage:DlgEditTextArray%:( aStrAddr&, anElement%, aPrompt$, aWidth% )See also: DlgEditText%: DlgEditTextEx%:Creates an editor for an element of a string array.L AldurDlgOpx!xdEdit dEditMulti DlgEditText%: DlgEditTextArray%: DlgEditTextMax%: DlgEditTextEx%: DlgEditTextArrayEx%: DlgEditTextMaxEx@fY YA9QADlgEditTextArrayEx%:R d"Usage:DlgEditTextArrayEx%:( aStrAddr&, anElement%, aPrompt$, aWidth%, lines%, flags& )See also: DlgEditText%: DlgEditTextEx%:Creates an editor for an element o?f a string array that allows extended options, including multi-line text.N AldurDlgOpx!xdEdit dEditMulti DlgEditText%: DlgEditTextArray%: DlgEditTextMax%: DlgEditTextEx%: DlgEditTextArrayEx%: DlgEditTextMaxEx7DlgEditTextEx%:DlgEditTextMaxEx%:DlgEditTextArrayEx%:R8 d7"OdP AldurDlgOpx!xdEdit dEditMulti DlgEditText%: DlgEditTextArray%: DlgEditTextMax%: DlgEditTextEx%: DlgEditTextArrayEx%: DlgEditTextMaxExDlgEditTextMax%:R d"Usage:DlgEditTextMax%:( aStrAddr&, aMaxLength%, aPrompt$, aWidth% )See also: DlgEditText%: DlgEditTextEx%:Edits a string with an imposed maximum length, or an element of an OPL+ structure.Q AldurDlgOpx!xdEdit dEditMulti DlgEditText%: DlgEditTextArray%: DlgEditTextMax%: DlgEditTextEx%: DlgEditTextArrayEx%: DlgEditTextMaxExDlgEditTextMaxEx%:R d"R S AldurDlgOpx!xdEdit dEditMulti DlgEditText%: DlgEditTextArray%: DlgEditTextMax%: DlgEditTextEx%: DlgEditTextArrayEx%: DlgEditTextMaxEx DlgEditTime%:R d "sUsage:DlgEditTime%:( BYREF aTime&, aPrompt$, flags%, aMin&, aMax& )See also: DlgEditDate%:Equivalent of dTime.TQ AldurDlgOpx!idDate dTime DlgEditDate%: DlgEditDateNoPop%: DlgEditTime%: DlgEditTimeAndDate%: DlgEditTimeAndDateNoPop%:DlgEditTimeAndDate%:R d"Usage:DlgEditTimeAndDate%:( BYREF aDate&, BYREF aTime&, aPrompt$, aBetween$, flags%, aMinDate&, aMinSecs&, aMaxDate&, aMaxSecs& )See also: DlgEditDate%:Allows both a time and date to be edited on one line.U AldurDlgOpx!idDate dTime DlgEditDate%: DlgEditDateNoPop%: DlgEditTime%: DlgEditTimeAndDate%: DlgEditTimeAndDateNoPop%:DlgEditTimeAndDateNoPop%:R d"Usage:DlgEditTimeAndDateNoPop%:( BYREF aDate&, BYREF aTime&, aPrompt$, aBetween$, flags%, aMinDate&, aMinSecs&, aMaxDate&, aMaxSecs& )See also: DlgEditDate%:Allows both a time and date to be edited on one line, but doesn't allow a pop-up calendar.V AldurDlgOpx!idDate dTime DlgEditDate%: DlgEditDateNoPop%: DlgEditTime%: DlgEditTimeAndDate%: DlgEditTimeAndDateNoPop%: DlgFile%:R  d "WX> AldurDlgOpx!dFile#DlgGetButtonText:DlgSetButtonText:R$ d#"YZ  AldurDlgOpx!DlgGetCaption:DlgSetCaption:R d"[7\ AldurDlgOpx! DlgGetFocus%:R d "] ^s AldurDlgOpx! DlgSetFocus%:!DlgGetTextLabel:DlgSetTextLabel:R" d!"_ ` AldurDlgOpx!DlgGetTrailer:DlgSetTrailer:R d"abb  AldurDlgOpx! DlgGetXXX:R  d "cd AldurDlgOpx!xDlgGetInt DlgGetLong DlgGetRangeLower DlgGetRangeUpper DlgGetRange DlgGetRangeLongLower DlgGetRangeLongUpper DlgGetRange DlgGroupEnd%:R d "Usage:DlgGroupEnd%:See also: DlgGroupStart%: DlgActivateInGroup%:Ends a group of overlaid controls (only one of which will be active at a time).e AldurDlgOpx!2OnStateChange DlgGroupStart%: DlgActivateInGroup%:D] AADlgSetWholeVisible%:DlgSetWholeVisibleLine%:DlgIsWholeVisible%:RB dA" AldurDlgOpx! DlgSetXXX:R  d "G AldurDlgOpx!xDlgSetInt DlgSetLong DlgSetRangeLower DlgSetRangeUpper DlgSetRange DlgSetRangeLongLower DlgSetRangeLongUpper DlgSetRangeDlgShowChoices%:R d"Usage:DlgShowChoices%:( aLine% )Can be used from a callback to bring up the selector-list of a DlgChoiceList%: control line (i.e., make the dialog behave as though the user had pressed TAB in that field). d"'h dh  d""?""_" AldurDlgOpx!dChoice DlgChoiceListDlgText%:DlgAnnotate%:R d" AldurDlgOpx!dTextLu-iEQm9-A2DlgGroupStart%:DlgGroupEnd%:DlgActivateInGroup%:R3 d2"g hm AldurDlgOpx! OnStateChange!DlgOnFocusLoss%:DlgOnFocusGain%:R" d!"ij AldurDlgOpx!Callback DlgOnLoad%:R  d "k$l AldurDlgOpx!CallBack)DlgOnStateChange%:DlgEnableStateChange%:R* d)"mn AldurDlgOpx!OnStateChange CallbackDlgOnValidate%:R d"o0#pF AldurDlgOpx!CallBack DlgPosition%:R d "qr` AldurDlgOpx!dPosition dInit DlgInit&:%DlgRadioButton%:DlgRadioButtonZero%:R& d%"st AldurDlgOpx!xdChoice DlgChoiceListItem%: DlgRadioButtonItem%: DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListDlgRadioButtonItem%:R d"Usage:DlgRadioButtonItem%:( aChoiceList$ )See also: DlgChoiceListItem%: DlgChoiceList%: DlgSetChoiceSeparator%:Alternate name for DlgChoiceListItem%: builds a list of choice-list, radio-button or combo-box items.uQ AldurDlgOpx!xdChoice DlgChoiceListItem%: DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListStringZero%: DlgRadioDlgRadioButtonZero%:R d"Usage:DlgRadioButtonZero%:( BYREF aButton%, aPrompt$, aFlags&, aWidth%, aButtonList$ )See also: DlgRadioButton%:Creates a radio-button control; indexing starts from zero (instead of one).v AldurDlgOpx!xdChoice DlgChoiceListItem%: DlgRadioButtonItem%: DlgChoiceList%: DlgChoiceListZero%: DlgChoiceListString%: DlgChoiceListDlgSetChoiceSeparator%:R d"wzx AldurDlgOpx!#dChoice DlgChoice DlgRadio DlgCombo/DlgSetDimmed%:DlgSetDimmedLine%:DlgIsDimmed%:R0 d/"yz AldurDlgOpx!(DlgSetDimmedButton%:DlgIsDimmedButton%:R) d("{| AldurDlgOpx! DlgSetFocus%:R d "}@~) AldurDlgOpx! DlgGetFocus%:DlgSetRetCode%:R d"n  AldurDlgOpx!CallBackDlgSetTitle%:(DlgGetTitle$:)R d"  AldurDlgOpx!2DlgSetVisible%:DlgSetVisibleLine%:DlgIsVisible%:R3 d2" AldurDlgOpx!@Table1title x dbodydapp x dsynonym x d@OOOOOOOO܂- U -psa%19OBH%NR]id*lq <A3GlLa (*438m<=>B@AFIKFNQAUWm[flhmnpr#uvvZy#|C} :Zݡ \|ߺ+3>Rv?  2<:_o^sw{hہW_(SáΣ٥aAC? w3!;@O&Y@C)@ .172႐- U -psa%19OBH%NR]id*lq <A3GlLa (*438m<=>B@AFIKFNQAUWm[flhmnpr#uvvZy#|C} :Zݡ \|ߺ+3>Rv?  2<:_o^sw{hہW_(SáΣ٥aAC? w3!,%4%$7mcU~\cd+REM -----------------------------------------------------REM AldurDlgDemo - Demonstration Program for AldurDlg.OPXREM Copyright (c) 2000-6 Graham L. Holden.REMREM This code demonstrates some of the possibilities whenREM using AldurDlg.OPX - You may freely use the ideas inREM this example code for your own use.REM -----------------------------------------------------include "Const.oph"include "System.oxh"include "AldurDlg.oxh"Const KSeenCascade& = &0001Const KSeenReactive& = &0002Const KSeenDynamic& = &0004Const KSeenValidate& = &0008Const KSeenReactive2& = &0010Const KSeenFileDlg& = &0020Const KMaxSeen% = 6proc WelcomeDialog: Global SeenMask&, SeenCount% Global KLF$(1) KLF$ = Chr$(10) DlgInit&:( "AldurDlg: Dialog extensions for OPL programs", KDlgDensePack% OR KDlgButRight% OR KADlgTrapEscape% ) DlgOnValidate%:( "ActOnButtons" ) DlgAnnotate%:( "", "AldurDlg Copyright Graham Holden, 2000-2006 Release 1.13", 0 ) DlgDividerAfter%: DlgAnnotate%:( "", "AldurDlg is an add-on OPX that provides an extended range of dialog functions", 0 ) DlgAnnotate%:( "", "for the OPL programmer. Using its features, you can create the sort of dynamic,", 0 ) DlgAnnotate%:( "", "interactive dialogs previously only available to C++ programmers.", 0 ) DlgAnnotate%:( "Cascadable dialogs", "Launch pop-up dialogs from one dialog in response" + KLF$ + "to button presses, validation routines etc.", KDTextAllowSelection% ) DlgAnnotate%:( "Reactive dialogs", "Callback to OPL when a control's value changes or" + KLF$ + "as the user moves from control to control.", KDTextAllowSelection% ) DlgAnnotate%:( "Dynamic controls", "Dim & hide controls; read or update their values" + KLF$ + "from any callback function.", KDTextAllowSelection% ) DlgAnnotate%:( "Validation", "Trap leaving a dialog (including ESCaping) so that"+ KLF$ + "settings can be cross-validated.", KDTextAllowSelection% ) DlgButton%:( "Change title", %T) DlgButton%:( "Read me first", %A ) DlgButton%:( "Select topic", KKeyEnter% OR KDButtonNoLabel% ) DlgExecute&:endpproc ActOnButtons%:( aLine%, aKeyCode& ) if aKeyCode& = KKeyEnter% if aLine% = 5 : DemoCascade%: elseif aLine% = 6 : DemoReactive%: elseif aLine% = 7 : DemoDynamic%: elseif aLine% = 8 : DemoValidate%: else gIPrint "ENTER on line " + Gen$( aLine%, 5 ) endif return KTrue% elseif aKeyCode& = 0 return DemoEscape%: elseif aKeyCode& = %A : DemoReadME%: elseif aKeyCode& = %T : DlgSetTitle%:( Gen$( Rnd * 1000000, 10 ) ) gIPrint Gen$( Rnd * 1000000, 10 ) endif return KTrue%endpproc AddToBuffer%:( aBuffer&, aString$ ) local offset&, saved% offset& = aBuffer& + 4 + PeekL( aBuffer& ) saved% = PeekB( offset& - 1 ) Poke$ offset& - 1, aString$ PokeB offset& - 1, saved% PokeL aBuffer&, PeekL( aBuffer& ) + Len( aString$ )endpproc DemoReadME%: local buffer&, KNL$(1) KNL$ = Chr$( KParagraphDelimiter% ) buffer& = Alloc( 4096 ) PokeL buffer&, 0 AddToBuffer%:( buffer&, "Welcome to AldurDlg Dialog enhancements for OPL" + KNL$ + KNL$ ) AddToBuffer%:( buffer&, "What is AldurDlg?" + KNL$ ) AddToBuffer%:( buffer&, "AldurDlg is an OPX an add-on module for OPL that brings extended dialog functionallity to OPL programs. " ) AddToBuffer%:( buffer&, "Using it, OPL programmers have access to a much wider range of the Psion's built-in support for dialogs. " ) AddToBuffer%:( buffer&, "There are additional and enhanced controls over those offered by OPL, and, most importantly, dialogs can " ) AddToBuffer%:( buffer&, "now be fully interactive: while one dialog is on screen, other secondary dialogs can be displayed; controls " ) AddToBuffer%:( buffer&, "can be dimmed, made wholly or partially hidden or reactivated; their current values can be read (for additional " ) AddToBuffer%:( buffer&, "validation, or to adjust other controls dynamically) and can be set. You can also have 'grouped' controls: two " ) AddToBuffer%:( buffer&, "or more controls, where only one is active at a time, that only take up one line of a dialog." + KNL$ + KNL$ ) AddToBuffer%:( buffer&, "Why AldurDlg?" + KNL$ ) AddToBuffer%:( buffer&, "OPL already provides a useful range of dialog functions, so why the need for more? My answer is that you only " ) AddToBuffer%:( buffer&, "have to look at how dialogs are used in 'native' programs on the Psion to realise that there is much that can be " ) AddToBuffer%:( buffer&, "done with them, that has not been made available to OPL programmers. Clearly, this enhanced functionallity existed " ) AddToBuffer%:( buffer&, "in the Psion's software (it's actually a layer called 'Eikon'), it just wasn't 'exposed' to OPL." ) AddToBuffer%:( buffer&, "" )REM dInit "About AldurDlg", KDlgFillScreen%REM dEditMulti buffer&, "", 30, 9, 4000REM Dialog DlgInit&:( "About AldurDlg", KDlgFillScreen% ORKDlgDensePack% ) DlgEditBuffer%:( buffer&, "", 30, 9, 4000, KADlgReadOnly& OR KADlgNoAutoSelection& ) DlgExecute&:endpproc MarkSeen%:( aSeenFlag& ) if NOT (SeenMask& AND aSeenFlag&) SeenMask& = SeenMask& OR aSeenFlag& SeenCount% = SeenCount% + 1 endifendpproc DemoEscape%: if SeenCount% = 0 dInit "You can't leave yet!" dText "", "You haven't looked at any of the new dialog features that" dText "", "AldurDlg makes available to OPL programmers!" elseif SeenCount% < KMaxSeen% dInit "Are you leaving already?" dText "", "You haven't yet seen all the features that this" dText "", "demonstration of AldurDlg has to offer." else dInit "Thank-you for looking" dText "", "You've seen everything this demonstration has to offer." dText "", "Now you can start using these features to give your own" dText "", "OPL programs a slicker and more dynamic interface!" endif if SeenCount% < KMaxSeen% dButtons "Sorry, I'm off", KKeyEsc%, "Ok, I'll stay", KKeyEnter% return Dialog <> 0 else dButtons "Goodbye", KKeyEnter% OR KDButtonNoLabel% Dialog return KFalse% endifendpproc DemoCascade%: MarkSeen%:( KSeenCascade& ) DlgInit&:( "Cacading dialogs", 0 ) DlgPosition%:( 0, -1 ) DlgText%:( "", "Events within one dialog, e.g. button presses, control-", $400 ) DlgText%:( "", "state changes, or moving from one control to another,", 0 ) DlgText%:( "", "can all launch cascading dialogs while the original is", 0 ) DlgText%:( "", "is still visible. There is no practical limit on how", 0 ) DlgText%:( "", "many dialogs can be shown.", 0 ) DlgButton%:( "Close", KKeyEsc% ) DlgButton%:( "Show another dialog", KKeyEnter% ) DlgOnValidate%:( "OnCascade1" ) DlgExecute&:endpproc OnCascade1%:( aLine%, aKeyCode& ) DlgInit&:( "Another cascaded dialog", 0 ) DlgPosition%:( -1, 1 ) DlgText%:( "", "Dialogs can be positioned around the", $400 ) DlgText%:( "", "screen, just as with normal OPL dialogs.", 0 ) DlgButton%:( "Close", KKeyEsc% ) DlgButton%:( "Show an OPL dialog", KKeyEnter% ) DlgOnValidate%:( "OnCascade2" ) return DlgExecute&: = 0endpproc OnCascade2%:( aLine%, aKeyCode& ) dInit "A cascaded OPL dialog" dPosition 1, 0 dText "", "Cascadable dialogs can be ordinary OPL dialogs," dText "", "although you cannot cascde further from them" dButtons "Close", -KKeyEsc%, "Close cascade", KKeyEnter% return Dialog = 0endpproc DemoReactive%: Global longID%, realID%, stringID%, checkID%, choiceID% local long&, real, string$(80),check%, choice% MarkSeen%:( KSeenReactive& ) long& = 1234 real = 3.1415 string$ = "How now brown cow" check% = KTrue% choice% = 3 DlgInit&:( "Reactive dialogs", KDlgButRight% ) DlgOnValidate%:( "OnReactiveValidate" ) DlgOnFocusLoss%:( "OnReactiveFocus" ) DlgOnStateChange%:( "OnReactiveChange" ) DlgText%:( "", "You can have AldurDlg make 'callbacks' to your OPL code when", 0 ) DlgText%:( "", "a control's value changes, or the user moves between controls", 0 ) DlgAnnotate%:( "", "Try moving between the controls below, and adjusting their values:", 0 ) longID% = DlgEditLong%:( long&, "A 'long' editor", 0, 100000 ) DlgEnableStateChange%: realID% = DlgEditFloat%:( real, "A floating-point editor", 0, 100 ) DlgEnableStateChange%: stringID% = DlgEditText%:( ADDR(string$), "A text editor", 15 ) DlgEnableStateChange%: checkID% = DlgCheckBox%:( check%, "A check-box" ) DlgEnableStateChange%: choiceID% = DlgChoiceList%:( choice%, "Select between", 0, 0, "First choice,Second choice,Third choice" ) DlgEnableStateChange%: DlgButton%:( "Reactive"+KLF$ +"Buttons", %B) DlgButton%:( "Reactive"+KLF$ +"Files", %F) DlgButton%:( "More", 13 ) DlgExecute&:endpproc OnReactiveValidate%:( aLine%, aKey&) if aKey&= 13 DemoReactive2%: return KTrue% elseif aKey&= %F DemoReactive3%: return KTrue% elseif aKey&= %B DemoReactive4%: return KTrue% endifendpproc OnReactiveFocus%:( aLine%, aDirection% ) if aDirection% < 0 if aLine% = longID% : gIPrint "Wrapping to the bottom" else gIPrint "Moving up" endif elseif aDirection%> 0 if aLine% = choiceID% : gIPrint "Back to the top" else gIPrint "Moving down" endif else gIPrint "You're standing still!" endifendpproc OnReactiveChange%:( aLine% ) if aLine% = longID% : gIPrint "Long: " + Gen$( DlgGetLong&:( aLine% ), 10 ) elseif aLine% = realID% : OnErr BadFloat:: gIPrint "Float: " + Gen$( DlgGetFloat:( aLine% ), 10 ) OnErr Off elseif aLine% = stringID% : gIPrint "String '" + DlgGetText$:( aLine% ) + "'" elseif aLine% = checkID% : if DlgGetCheckBox%:( aLine% ) gIPrint "Check-box ticked" else gIPrint "Check-box cleared" endif elseif aLine% = choiceID% : gIPrint "Choice: " + Gen$( DlgGetChoice%:( aLine% ), 10 ) endif return KFalse%BadFloat:: OnErr Off gIPrint "Bad float value!" +ERR$(ERR)endpproc DemoReactive2%: Global intID%, dateID%, timeID%, rangeID% local int%, date&, time&, rangeLo%, rangeHi% MarkSeen%:( KSeenReactive2& ) int% = 123 date& = DAYS(DAY, MONTH, YEAR) time& = HOUR * 3600.0 + MINUTE * 60 + SECOND rangeLo%= 33 rangeHi%= 66 DlgInit&:( "More reactive dialogs", 0 ) DlgOnStateChange%:( "OnReactiveChange2" ) DlgText%:( "", "Here are some more reactive controls", 0 ) intID% = DlgEditInt%:( int%, "An 'integer' editor", 0, 1000 ) DlgEnableStateChange%: dateID% = DlgEditDate%:( date&, "A date editor", 0, DAYS(31,12,2099) ) DlgEnableStateChange%: timeID% = DlgEditTime%:( time&, "A time editor", 9, 0, 86399 ) DlgEnableStateChange%: rangeID% = DlgEditRange%:( rangeLo%, " to ", rangeHi%, "A range editor", 0, 100 ) DlgEnableStateChange%: DlgExecute&:endpproc OnReactiveChange2%:( aLine% ) if aLine% = intID% : gIPrint "Int: " + Gen$( DlgGetInt%:( aLine% ), 10 ) elseif aLine% = dateID% : gIPrint "Date: " + Gen$( DlgGetDate&:( aLine% ), 10 ) elseif aLine% = timeID% : giPrint "Time: " + Gen$( DlgGetTime&:( aLine% ), 10 ) elseif aLine% = rangeID% : gIPrint "Range: "+ Gen$( DlgGetRangeLower%:( aLine% ), 10 ) + ""+Gen$( DlgGetRangeUpper%:( aLine% ), 10 ) endif return KFalse%endpproc DemoReactive3%: local file$( 255 ) Global idFile%, idComment% file$ = "c:\" Busy "Busy scanning for matching files", KBusyBottomLeft%, 1 DlgInit&:( "Reactive file controls", 0 ) DlgOnLoad%:( "OnReactiveLoad3" ) DlgOnStateChange%:( "OnReactiveChange3" ) DlgOnValidate%:( "OnReactiveValidate3") DlgText%:( "", "Here's an example of the AldurDlg equivalent to 'dFile',", 0 ) DlgText%:( "", "but reacting dynamically as files are selected", 0 ) DlgAnnotate%:("", "Try selecting a file less than 10k in size and see what happens!", 0 ) idFile%= DlgFile%:( Addr( file$ ), "", 0 ) DlgEnableStateChange%: idComment% = DlgAnnotate%:( "Comment", "<>NEEDLOTSOFSPACEFORLONGESTMESSAGE", 0 ) Busy OFF DlgExecute&:endpproc GetFileSize&:( aFilename$ ) local posn&, size&, fd% posn& = 0 ioOpen( fd%, aFilename$, $600 ) ioSeek( fd%, 2, posn&) ioClose( fd%) return posn&endpproc GetFileSize$:( aFilename$ ) local size& size& = GetFileSize&:( aFilename$ ) if size& < 1024 : return Gen$( size&, 5 ) + " bytes" elseif size& < &100000 : return Gen$( size&/&400, 5 ) + "kB" else return Gen$( size&/&100000, 10 ) + "MB" endifendpproc OnReactiveLoad3%:REM Force an "OnChange" event to fill-in the initial file's detailsREM OnReactiveChange3%:( idFile%)endpproc OnReactiveChange3%:( aLine% )REM 'idFile%' refers to the file-part of the selector; theREM folder and disk parts will be the next two lines.REM if (idFile%<= aLine%) AND(aLine%<= idFile% + 2) if DlgGetFile$:( idFile%) <>"" DlgSetTextLabel%:( idComment%, GetFileSize$:( DlgGetFile$:( idFile%) ) + " - Comment text for "+DlgGetFile$:( idFile%) ) else DlgSetTextLabel%:( idComment%, "-- no files in directory --") endif endifendpproc OnReactiveValidate3%:( aLine%, aKey&) if aKey& = 13 if DlgGetFile$:( idFile%) = "" gIPrint "Please select a file" return KTrue% elseif GetFileSize&:( DlgGetFile$:( idFile%) ) < 10240 gIPrint "Please select a file larger than 10k" return KTrue% endif endifendpproc DemoReactive4%: Global idFile%, idDir% local fileNo%, dirNo% DlgInit&:( "Reactive buttons", 0 ) DlgOnFocusLoss%:( "OnReactiveFocus4") DlgOnLoad%:("OnReactiveLoad4") idFile% = DlgChoiceList%:(fileNo%, "File", 0,0, "Filename 1,Filename 2,Filename 3") idDir% = DlgChoiceList%:( dirNo%, "Path", 0,0, ",Directory 1,Directory 2,Directory 3") DlgButton%:("Cancel", -27 ) DlgButton%:( "Change"+KLF$ +"directory", 13 ) DlgExecute&:endpproc OnReactiveLoad4%: OnReactiveFocus4%:( idDir%, 0 ) dInit "OnLoad events" dPosition 0, 1 dText "", "Dialogs can also call an 'OnLoad' funtion," dText "", "Which is called just prior to user-interaction" dText "", "with the dialog. This can be useful to show" dText "", "user-help, or to initialise dynamic controls." dText "", "", 2 Dialogendpproc OnReactiveFocus4%:( aLine%, aDirection%) if aLine% = idDir% DlgSetButtonText%:( -2, "Open"+KLF$ +"File" ) else DlgSetButtonText%:( -2, "Change"+KLF$ +"directory" ) endifendpproc DemoDynamic%: Global choiceID%, timeID%, checkID%, subjectID% local choice%, time&, check%, subject$( 80 ) MarkSeen%:( KSeenCascade& ) time& = (&1 * 3600 * HOUR) + (60 * MINUTE) + SECOND DlgInit&:( "Dynamic dialogs", 0 ) DlgOnStateChange%:( "OnDynamicChange" ) DlgOnValidate%:( "OnDynamicValidate" ) DlgAnnotate%:( "", "Dialog controls can now be dynamic they can be disabled (dimmed), made partially", 0 ) DlgAnnotate%:( "", "or wholly invisible, and restored to normal. Their values can be set, and groups of", 0 ) DlgAnnotate%:( "", "controls can 'overlay' each other so that only one is active at a time.", 0 ) choiceID% = DlgChoiceListZero%:( choice%, "When should fax be sent?", 0, 0, "Immediately,At specified time" ) DlgEnableStateChange%: timeID% = DlgEditTime%:( time&, " Time to send", 0, 0, 84599 ) DlgSetDimmed%:( choice% = 0 ) checkID% = DlgCheckBox%:( check%, "Use subject line" ) DlgEnableStateChange%: subjectID% = DlgEditText%:( ADDR(subject$), " Subject line", 15 ) DlgSetWholeVisible%:( check% ) DlgButton%:( "Close", -KKeyEsc% ) DlgButton%:( "Use 'default' values", %D ) DlgButton%:( "See grouped controls", KKeyEnter% ) DlgExecute&:endpproc OnDynamicValidate%:( aLine%, aKeyCode& ) if aKeyCode& = %D DlgSetChoice%:( choiceID%, 1 ) DlgSetTime%:( timeID%, (&1 * 3600 * (HOUR + 3)) + (60 * MINUTE) + SECOND ) DlgSetDimmedLine%:( timeID%, KFalse% ) DlgSetCheckBox%:( checkID%, KTrue% ) DlgSetText%:( subjectID%, "Here's the fax you asked for" ) DlgSetWholeVisibleLine%:( subjectID%, KTrue% ) return KTrue% elseif aKeyCode& = KKeyEnter% DynamicGroup%: return KTrue% endifendpproc OnDynamicChange%:( aLine% ) if aLine% = choiceID% : DlgSetDimmedLine%:( timeID%, DlgGetChoice%:( choiceID% ) = 0 ) elseif aLine% = checkID% : DlgSetWholeVisibleLine%:( subjectID%, DlgGetCheckBox%:( checkID% ) ) endifendpproc DynamicGroup%: Global choiceID%, groupID% local choice%, findDate&, findStr$(30), findAmount local d%, m%, y% findDate& = DAYS( DAY, MONTH, YEAR ) DlgInit&:( "Grouped controls", 0 ) DlgOnStateChange%:( "OnDynamicGroup" ) DlgAnnotate%:( "", "This shows how a versatile 'Find' dialog can be constructed:", 0 ) choiceID% = DlgChoiceListZero%:( choice%, "What to search", 0, 0, "Date,Description,Amount" ) DlgEnableStateChange%: groupID% = DlgGroupStart%: DlgEditDate%:( findDate&, " Date", 0, DAYS( 31,12,9999 ) ) DlgEditText%:( ADDR(findStr$), " Description", 15 ) DlgEditFloat%:( findAmount, " Amount", 0, 99999.99 ) DlgGroupEnd%: DlgActivateInGroup%:( groupID% + choice% ) if DlgExecute&: <> 0 if choice% = 0 DaysToDate findDate&, y%, m%, d% gIPrint "Searching for date "+Gen$( d%, 2) +"/"+Right$( "0"+Gen$( m%, 2 ), 2 )+"/"+Gen$(y%, 4 ) elseif choice% = 1 gIPrint "Searching for "+Chr$(34)+findStr$+ Chr$(34) elseif choice% = 2 gIPrint "Searching for amount "+Fix$( findAmount, 2, 10 ) endif endifendpproc OnDynamicGroup%:( aLine% ) DlgActivateInGroup%:( groupID% + DlgGetChoice%:( choiceID% ) )endpproc DemoValidate%: Global long1ID%, long2ID%, stringID% local long1&, long2&, string$( 9 ) MarkSeen%:( KSeenValidate& ) long1& = 9876 long2& = 124 DlgInit&:( "Validated dialog", 0 ) DlgOnValidate%:( "OnValidateValidate" ) DlgText%:( "", "You can set an OPL routine to act as a 'validate' routine for a dialog.", 0 ) DlgAnnotate%:( "", "This can check that two or more settings are mutually correct, or can impose additional conditions", 0 ) DlgAnnotate%:( "", "on controls beyond the 'allowed range' that is available for numeric editors.", 0 ) long1ID% = DlgEditLong%:( long1&, "First number", 0, 9999 ) long2ID% = DlgEditLong%:( long2&, "Second number", 0, 9999 ) stringID%= DlgEditText%:( ADDR(string$), "National Insurance no.", 10 ) DlgAddTrailer%:( "e.g. AB123456C") DlgButton%:( "Notes", %N ) DlgButton%:("Accept", KKeyEnter% ) if DlgExecute&: dInit "Results" dText "Numbers total", Gen$(long1&+ long2&, 10 ) dText "N.I. Number", Upper$( Left$( string$, 2 ))+" "+ Mid$(string$, 3, 6)+" "+ Upper$( Right$( string$, 1 )) dButtons "Continue", KKeyEnter%OR KDButtonNoLabel% Dialog endifendpproc OnValidateValidate%:( aLine%, aKeyCode& ) local NIbad%, NIstr$(9) if aKeyCode& = %N dInit "Validate notes" dPosition -1, -1 dText "", "As well as checking the format of the NI number in the" dText "", "OnValidate%: callback, it might be sensible to also check" dText "", "it in the OnFocusLoss%: callback, as the user leaves" dText "", "the field. Checking it in the OnStateChange%: callback" dText "", "would probably be very annoying, unless a much more" dText "", "sophisticated routine were used, that checks that the" dText "", "string 'hasn't definitely gone wrong yet' (i.e. '4' would" dText "", "be rejected; 'a' wouldn't; 'a4' would; 'ab5' wouldn't;" dText "", "'ab5a' would, etc.)." Dialog return KTrue% endif if DlgGetLong&:( long1ID% ) + DlgGetLong&:( long2ID% ) > 9999 gIPrint "The two numbers must total less than 10,000" if aLine% = stringID% DlgSetFocus%:( long1ID% ) endif return KTrue% endif REM This isn't a very elegant way of checking the number, but REM what the hell; it works, and I'm trying to show of the new REM dialog stuff... REM NIstr$ = DlgGetText$:( stringID% ) if Len( NIstr$ ) <> 9 : NIbad% = KTrue% elseif Asc(Upper$(Mid$( NIstr$, 1, 1 ))) < %A : NIbad% = KTrue% elseif Asc(Upper$(Mid$( NIstr$, 1, 1 ))) > %Z : NIbad% = KTrue% elseif Asc(Upper$(Mid$( NIstr$, 2, 1 ))) < %A : NIbad% = KTrue% elseif Asc(Upper$(Mid$( NIstr$, 2, 1 ))) > %Z : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 3, 1 ) ) < %0 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 3, 1 ) ) > %9 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 4, 1 ) ) < %0 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 4, 1 ) ) > %9 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 5, 1 ) ) < %0 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 5, 1 ) ) > %9 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 6, 1 ) ) < %0 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 6, 1 ) ) > %9 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 7, 1 ) ) < %0 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 7, 1 ) ) > %9 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 8, 1 ) ) < %0 : NIbad% = KTrue% elseif Asc( Mid$( NIstr$, 8, 1 ) ) > %9 : NIbad% = KTrue% elseif Asc(Upper$(Mid$( NIstr$, 9, 1 ))) < %A : NIbad% = KTrue% elseif Asc(Upper$(Mid$( NIstr$, 9, 1 ))) > %Z : NIbad% = KTrue% endif if NIbad% DlgSetFocus%:( stringID%) dInit "Incorrect NI format" dText "", "A National Insurance number should be formed from two letters," dText "", "followed by six digits, followed by another letter, e.g. 'AB123456C'." dButtons "Try again", KKeyEnter% OR KDButtonNoLAbel% Dialog return KTrue% endifendpproc StandardDialog%: Global text$( 20 ), int%, long&, real Global time&, date&, tdTime&, tdDate& local dlg&, yy%, mm%, dd% InitialiseDialogVariables%: do DlgInit&:( "AldurDlg: Dialog extensions for OPL programs", KDlgDensePack% ) DlgOnValidate%:( "StdOnValidate" ) DlgText%:( "", "Welcome to the wonderful world of enhanced dialogs!", 1 ) DlgAnnotate%:( "", "AldurDlg Copyright Graham Holden, 2000-2001", 1 ) DlgDividerAfter%: DlgEditText%:( ADDR(text$), "Text editor", 0 ) DlgEditLong%:( long&, "Long editor", 0, 100000 ) DlgEditReal%:( real, "Float editor", -100, 100 ) DlgEditInt%:( int%, "Plus! Int editor", 0, 100 ) DlgAnnotate%:( " ", "You can now edit integers (e.g. myVal%) directly!", 0 ) DlgButton%:( "Time & Date", %T ) DlgButton%:( "Strings", %s ) dlg& = DlgExecute&: Cls if dlg& = 0 print "You ESCaped from the dialog!" else print "You accepted the changes with exit code", dlg& endif print print "Text string "; Chr$(34); text$; Chr$(34) print "Integer "; int% print "Long integer "; long& print "Floating point "; real print "Time "; Int(time&/3600.0); ":"; Int(Mod&:(time&,3600)/60.0); ":"; Mod&:(time&,60) DaysToDate date&, yy%, mm%, dd% print "Date "; dd%; "/"; mm%; "/"; yy% DaysToDate tdDate&, yy%, mm%, dd% print "Time & date "; Int(time&/3600.0); ":"; Int(Mod&:(time&,3600)/60.0); ":"; Mod&:(time&,60), dd%; "/"; mm%; "/"; yy% print print "Press ESC to quit, any other key to run the dialog again"; until Get = 27 main:endpproc InitialiseDialogVariables%: text$ = "Max. 20 chars. long" int% = 42 long& = 54321 real = 3.1415926endpproc StdOnValidate%:( aLine%, aKeyCode& ) if aKeyCode& = %s TimeAndDateDialog%: return KTrue% elseif aKeyCode& = %t StringsDialog%: return KTrue% endifendpproc TimeAndDateDialog%: DlgInit&:( "Time and date controls", 0 ) DlgPosition%:( -1, -1 )  DlgExecute&:endpproc StringsDialog%: DlgInit&:( "String controls", 0 ) DlgExecute&:endpPROC main: Global selID%, grpID%, long1ID%, long2ID%, floatID%, rangeID%, iID%, uID%, dateID%, textID%, testID%, checkID%, radioID%, comboID% local c%, i%, m&, n, o&, p&, q&, t$(237), u$(2, 15), dt&, check%, radio%, combo$( 40 ) local dd%, mm%, yy%, time& Global testOpt% testOpt% = 1 i% = 99 m& = Addr( t$ ) n = 2222.22 o& = 33 p& = 44 q& = 155 t$ = "aBcDeFg" u$(1) = "1234567890" u$(2) = "abcdef" dt& = Days( DAY, MONTH, YEAR ) do DlgInit&:( "AldurDlg Demonstration: Dialog extensions for OPL programs", KDlgDensePack% OR KDlgButRight% ) DlgOnFocusLoss%:( "OnFocusLoss" ) DlgOnValidate%:( "OnValidate" ) DlgOnStateChange%:( "OnStateChange" ) DlgText%:( "", "Welcome to the wonderful world of enhanced dialogs!", $001 ) DlgAnnotate%:( "", "AldurDlg Copyright Graham Holden, 2000-2001", $201 ) iID% = DlgEditInt%:( testOpt%, "Enter integer", -100, 100 ) DlgAddTrailer%:( "days" ) DlgEnableStateChange%:if 0 dateID% = DlgEditDate%:( dt&, "Date", Days( 1,1,1960 ), Days( 31,12,2100 ) ) DlgEnableStateChange%: DlgEditTime%:( time&, "Time", 1, 0, 86399 )else dateID% = DlgEditTimeAndDate%:( dt&, time&, "Time", " and date ", 1, Days( 1,1,1960 ), 0, Days( 31,12,2100 ), 0 ) DlgEnableStateChange%:endif DlgSetChoiceSeparator%:( %: ) DlgChoiceListItem%:( "1st integer:2nd integer:Floating-point" ) DlgSetChoiceSeparator%:( %, ) selID% = DlgChoiceListZero%:( c%, "Choose from", 0, 10, "" ) DlgEnableStateChange%: DlgAnnotate%:( "", "Use the control above to select which numerical editor below is active", $000 ) DlgGroupStart%: long1ID% = DlgEditLong%:( m&, "Enter 1st number", -&80000000, &7fffffff ) long2ID% = DlgEditLong%:( o&, "Enter 2nd number", -100, 100 ) floatID% = DlgEditReal%:( n, "Enter real number", -100, 100 ) grpID% = long1ID% DlgGroupEnd%: DlgActivateInGroup%:( c% + grpID% ) DlgGroupStart%: DlgAnnotate%:( " ", "Enter the first long-integer number", $600 ) DlgAnnotate%:( " ", "Enter the second long-integer number", $600 ) DlgAnnotate%:( " ", "Enter the floating-point number", $600 ) DlgGroupEnd%: DlgActivateInGroup%:( c% + grpID% + 3 ) rangeID% = DlgEditRangeLong%:( p&, " to ", q&, "Enter range", -100, 100 ) DlgEnableStateChange%: DlgAddTrailer%:( "inches" ) textID% = DlgEditText%:( Addr( t$ ), "Artist and album", 18 ) print "textid", textid% DlgEnableStateChange%: DlgGroupStart%: uID% = DlgEditTextArray%:( Addr( u$() ), 1, "U$(1)", 10 ) DlgEditTextArray%:( Addr( u$() ), 2, "U$(2)", 10 ) DlgGroupEnd%: DlgActivateInGroup%:( (i% AND 1) + uID% ) checkID% = DlgCheckBox%:( check%, "To tick, or not to tick" ) DlgEnableStateChange%: radio% = 2 radioID% = DlgRadioButton%:( radio%, "Choose one", "Choice 1,Choice 2,Choice 3" ) DlgEnableStateChange%: comboID% = DlgComboBox%:( Addr(combo$), "Combination box", 10, "zzz,aaa,bbb,ccc" ) DlgEnableStateChange%:REM testID% = DlgTest%:( testOpt% )REM DlgEnableStateChange%: DlgButton%:( "Fred", %F ) DlgButton%:( "Alf", %a ) DlgButton%:( "Bert", %B OR $200 ) DlgButton%:( "Button 1", %Z ) DlgButton%:( "Button 2", 13 ) print print "Dialog returned "; DlgExecute&: print "Integer "; i% print "Long "; m& print "Real "; n print "2nd Long "; o& print "Range "; p&; ".."; q& print "Choice list ";c% print "String "; "--"; t$; "--", "("; Len(t$); ")" print "U$(1) "; u$(1) print "U$(2) "; u$(2) DaysToDate dt&, yy%, mm%, dd% print "Date "; dd%; "/"; mm%; "/"; yy% print "Time "; Int(time&/3600.0); ":"; Int(Mod&:(time&,3600)/60.0); ":"; Mod&:(time&,60) print "Check "; check% print "Radio "; radio% print "Combo "; combo$ print "Finished." until Get = 27endpproc button%:( aLine%, aKeyCode& ) gIPrint "line:" + Gen$( aLine%, 5 ) + ", code:" + Gen$( aKeyCode&, 10 )endpproc OnStateChange%:( aLine% ) if 0 elseif aLine% = iID% : DlgActivateInGroup%:( (DlgGetInt%:( iID% ) AND 1) + uID% ) elseif aLine% = selID% : DlgActivateInGroup%:( DlgGetChoice%:( selID% ) + grpID% ) DlgActivateInGroup%:( DlgGetChoice%:( selID% ) + grpID% + 3 ) elseif aLine% = rangeID% : gIPrint "Lower range " + Gen$( DlgGetRangeLongLower&:( rangeID% ), 5 ) elseif aLine% = dateID% : gIPrint DateStr$:( DlgGetDate&:( dateID% ) ) elseif aLine% = textID% : gIPrint "--" + DlgGetText$:( textID% ) + "--" elseif aLine% = testID% : if testOpt% = 1 : gIPrint "Make up your mind!" elseif testOpt% = 2 : gIPrint "Just checking" elseif testOpt% = 3 : gIPrint "Please do not press this button again" elseif testOpt% = 4 : gIPrint "4444" : get endif elseif aLine% = checkID% : gIPrint "Check: " + Gen$( DlgGetCheckBox%:( checkID% ), 5 ) elseif aLine% = radioID% : gIPrint "Radio: " + Gen$( DlgGetRadio%:( radioID% ), 5 ) elseif aLine% = comboID% : gIPrint "Combo--" + DlgGetComboBox$:( comboID% ) + "--" endifendpproc OnFocusLoss%:( aLine%, aDirection% ) if 0 elseif aLine% = textID% : gIPrint "--" + DlgGetText$:( textID% ) + "--" elseif aDirection% < 0 : gIPrint "Going up" elseif aDirection% > 0 : gIPrint "Going down" else gIPrint "Staying put!" endifendpproc OnValidate%:( aLine%, aKeyCode& ) if aKeyCode& = %Z gIPrint "Check: " + Gen$( DlgGetCheckBox%:( checkID% ), 5 ) DlgSetText%:( textID%, "bibble" ) DlgSetComboBox%:( comboID%, "how now brown cow" ) DlgSetRadio%:( radioID%, 3 ) SubsidiaryDialog%: return KTrue% endif if DlgGetLong&:( long1ID% ) = DlgGetLong&:( long2ID% ) gIPrint "1st and 2nd numbers cannot be the same", KBusyTopRight% if DlgGetChoice%:( selID% ) = floatID% - grpID% DlgActivateInGroup%:( long1ID% ) DlgActivateInGroup%:( long1ID% + 3 ) DlgSetChoice%:( selID%, long1ID% - grpID% ) endif DlgSetFocus%:( grpID% ) return KTrue% endif if Loc( DlgGetText$:( textID% ), "," ) = 0 dInit "Bad album, artist" dText "", "Your artist and album selection do not appear to be valid", 2 dText "", "(" + DlgGetText$:( textID% ) + ")", 2 dButtons "Re-enter", -$11B, "Use anyway", $10D if Dialog = 0 return KTrue% endif DlgSetFocus%:( textID% ) endif if DlgGetRangeLongLower&:( rangeID% ) = DlgGetRangeLongUpper&:( rangeID% ) gIPrint "Range end-points must be different", KBusyTopRight% DlgSetFocus%:( rangeID% ) return KTrue% endif if DlgGetReal:( floatID% ) < 10.0 gIPrint "Number must be 10.0 or greater", KBusyTopRight% DlgActivateInGroup%:( floatID% ) DlgActivateInGroup%:( floatID% + 3 ) DlgSetChoice%:( selID%, floatID% - grpID% ) DlgSetFocus%:( floatID% ) return KTrue% endifendpproc SubsidiaryDialog%: Global artistID%, albumID% local artist%, album%(3) local string$( 255 ) DlgInit&:( "This is your second dialog", 0 ) DlgOnStateChange%:( "ArtistChange" ) artistID% = DlgChoiceListZero%:( artist%, "Artist", 0, 0, "AC/DC,Motrhead,Saxon" ) DlgEnableStateChange%: DlgGroupStart%: albumID% = DlgChoiceListZero%:( album%(1), "Album", 0, 0, "Powerage,Highway to Hell,Hell's Bells" ) DlgChoiceListZero%:( album%(2), "Album", 0, 0, "Motrhead,Overkill,Bomber" ) DlgChoiceListZero%:( album%(3), "Album", 0, 0, "Wheels of Steel,Strong Arm of the Law,Dogs of War" ) DlgGroupEnd%: DlgActivateInGroup%:( artist% + albumID% ) if DlgExecute&: = 13 gIPrint "Artist:" + Gen$( artist%, 5 ) + ", album:" + Gen$( album%( artist% + 1 ), 5 ) if artist% = 0 : if album%(1) = 0 : string$ = "AC/DC, Powerage" elseif album%(1) = 1 : string$ = "AC/DC, Highwaw to Hell" elseif album%(1) = 2 : string$ = "AC/DC, Hell's Bells" endif elseif artist% = 1 : if album%(2) = 0 : string$ = "Motrhead, Motrhead" elseif album%(2) = 1 : string$ = "Motrhead, Overkill" elseif album%(2) = 2 : string$ = "Motrhead, Bomber" endif elseif artist% = 2 : if album%(3) = 0 : string$ = "Saxon, Wheels of Steel" elseif album%(3) = 1 : string$ = "Saxon, Strong Arm of the Law" elseif album%(3) = 2 : string$ = "Saxon, Dogs of War" endif endif DlgSetText%:( textID%, string$ ) endifendpproc ArtistChange%:( aLine% ) if aLine% = artistID% DlgActivateInGroup%:( DlgGetChoice%:( artistID% ) + albumID% ) endifendpproc DateStr$:( aDate& ) local dd%, mm%, yy% DaysToDate aDate&, yy%, mm%, dd% return Gen$( dd%, 2 ) + "/" + Right$( "0" + Gen$( mm%, 2 ), 2 ) + "/" + Right$( "000" + Gen$( yy%, 5 ), 4 )endpproc DebugInt%:( aPrompt$, aInt& ) if 0 gIPrint aPrompt$ + ": " + Gen$( aInt&, 12 ) + " (" + HEX$( aInt& ) + ")" else dInit "DebugInt" dText aPrompt$, Gen$( aInt&, 10 ) + " (" + HEX$( aInt& ) + ")" dButtons "Ok", $10D Dialog endifendpproc DlgDebug%:( prompt$, number&) dInit "DlgDebug" dText prompt$, Gen$( number&, 10 ) dButtons "Continue", $10D Dialogendp\c ~efd\c~efd.A*Texted.app~~7mcU2\cd9REM -----------------------------------------------------------REM AldurDlg.oxh, version 1.13REM Header File for AldurDlg.OPXREM Copyright (c) Graham L. Holden, 2000-2006.REM -----------------------------------------------------------REM See documentation for main license conditions; in brief:REM o Everyone is allowed, for free, to have/use the OPX so thatREM programs using it can execute;REM o Everyone may develop programs that use the OPX, but areREM not allowed to charge FOR the OPX and must inform usersREM that the OPX component is freely available.REM o Enhancements TO the OPX are allowed providing free accessREM to both source and the OPX is maintained.REMREM OPX Skeleton originally adapted from TOPX in Symbian's SDKREM -----------------------------------------------------------REM -----------------------------------------------------------REM OPX identifier and versionConst KUidAldurDlg& = &101f9bf0Const KAldurDlgVersion% = $010dREM -----------------------------------------------------------REM Addtional flag to DlgInit&: that allows trapping of ESCREM through the OnValidate%: callback.Const KAdlgExactKeys% = $2000Const KADlgTrapEscape% = $4000REM -----------------------------------------------------------REM Options to DlgCallbackOptions&: that affect how/whenREM callbacks are made.Const KAdlgFocusGainOnLoad& = $0001Const KADlgFocusLossOnClose& = $0002Const KADlgSuppressInfoMsg& = $0004Const KADlgNoFocusChangeIfNoMove& = $0008Const KAdlgFocusGainAfterRefusal& = $0010REM -----------------------------------------------------------REM These are flag values that can be used with the DlgEditText*REM family of calls (including DlgEditBuffer%:).Const KADlgWidthInPixels& = &00000004 REM Specified width is in pixelsConst KADlgNoAutoSelection& = &00000008 REM Does not initially highlight textConst KADlgJustAutoCurEnd& = &00000010 REM Positions cursor at end of stringConst KADlgNoWrap& = &00000020 REM In multi-line, does not wrap, Sh-Enter adds newlineREM KADlgLineCursor& = &00000040 REM ?? doesn't seem to make a differenceConst KADlgNoHorizScrolling& = &00000080 REM Does not partially scroll text, each (not useful with above)REM KADlgInclusiveSizeFixed& = &00000100 REM ?? to do with scroll bars?Const KADlgAlwaysShowSelection& = &00001000 REM Shows highlighted text even if not on lineConst KADlgReadOnly& = &00002000 REM Displayed as an editor/scrollable, but cannot editConst KADlgAllowUndo& = &00008000 REM Enable undo bufferConst KADlgNoLineOrParaBreaks& = &00010000 REM Prevents Sh-Enter being usedREM -----------------------------------------------------------REM These are flag values that can be used with the DlgFile%: inREM addition to (most) standard OPL flags:Const KADlgNoDriveSelector& = &00001000 REM Don't show drive selector.Const KADlgNoFolderSelector& = &00002000 REM Don't show folder selector.Const KADlgNoDriveOrFolder& = &00003000 REM Combination of above.Const KADlgSelectorWidth& = &00010000 REM Allows width of folder/file selector to be set.REM -----------------------------------------------------------REM Constants that can be used with date/time editorsREM KMaxDate& isn't really the maximum date, but probably theREM most useful, since it restricts the year to four digits.REM KReallyMaxDate& allows the maximum possible date/time valueREM within EPOC: 03:41:43 pm on 13 Jan 35,970. This should beREM more than long enough for any Psion!Const KMaxTime& = &1517f REM 86399 seconds = 11:59:59 pmConst KMaxDate& = &2d247f REM 31 Dec 9,999Const KReallyMaxDate& = &6525121 REM 27 Dec 292,276Const KYearZero& = -&a96d5 REM 1 Jan 0000REM -----------------------------------------------------------REM These button-ids should be used in calls to DlgSetButtonText%REM and DlgGetButtonText% for the non-letter buttons.Const KBidCancel% = -1Const KBidOk% = -2Const KBidTab% = -3Const KBidDelete% = -4Const KBidSpace% = -5REM -----------------------------------------------------------REM Declaration of the OPX and its entry points.Declare OPX AldurDLG, KUidAldurDlg&, KAldurDlgVersion% DlgTest%:( aNumber%, aString$) : 999 DlgInit&:( aTitle$, aFlags& ) : 1 DlgExecute&: : 2 REM DlgPage : 3 DlgGroupStart%: : 4 DlgGroupEnd%: : 5 DlgButton%:( aLabel$, aHotKey%) : 6 DlgSetRetCode%:( aRetCode%) : 7 DlgDismissDialog%: : 8 DlgCallbackOptions&:( options&) : 9 DlgEditInt%:( BYREF aInt%, aPrompt$, aMin%, aMax% ) : 100 DlgEditLong%:( BYREF aInt&, aPrompt$, aMin&, aMax& ) :101 DlgEditReal%:( BYREF aFloat, aPrompt$, aMin , aMax ) :102 DlgEditFloat%:( BYREF aFloat, aPrompt$, aMin , aMax ) :102 REM Synonym DlgEditRange%:( BYREF aLower%, aSep$, BYREF aUpper%, aPrompt$, aMin%, aMax% ) : 103 DlgEditRangeLong%:( BYREF aLower&, aSep$, BYREF aUpper&, aPrompt$, aMin&, aMax& ) : 104 DlgEditDate%:( BYREF aDate&, aPrompt$, aMin&, aMax& ) :105 DlgEditDateNoPop%:( BYREF aDate&, aPrompt$, aMin&, aMax& ) :106 DlgEditTime%:( BYREF aTime&, aPrompt$, aFlags%, aMin&, aMax& ) :107 DlgEditTimeAndDate%:( BYREF aDate&, BYREFaTime&, aPrompt$, aBetween$, aFlags%, aMinDate&, aMinSecs&, aMaxDate&, aMaxSecs& ) :108 DlgEditTimeAndDateNoPop%:( BYREF aDate&, BYREFaTime&, aPrompt$, aBetween$, aFlags%, aMinDate&, aMinSecs&, aMaxDate&, aMaxSecs& ) :109 DlgEditText%:( aStrAddr&, aPrompt$, aWidth% ) : 110 DlgEditTextMax%:( aStrAddr&, aMaxLength%, aPrompt$, aWidth% ) : 111 DlgEditTextArray%:( aStrAddr&, aArrayElem%, aPrompt$, aWidth% ) : 112 DlgEditTextEx%:( aStrAddr&, aPrompt$, aWidth%, aLines%, aFlags&) : 113 DlgEditTextMaxEx%:( aStrAddr&, aMaxLength%, aPrompt$, aWidth%, aLines%, aFlags&) : 114 DlgEditTextArrayEx%:( aStrAddr&, aArrayElem%, aPrompt$, aWidth%, aLines%, aFlags&) : 115 DlgEditBuffer%:( aBufAddr&, aPrompt$, aWidth%, aLines%, aMaxLength&, aFlags&) : 116 DlgChoiceListItem%:( aChoiceList$ ) : 117 DlgRadioButtonItem%:( aChoiceList$ ) : 117 REM duplicate DlgChoiceList%:( BYREF aChoice%, aPrompt$, aFlags&, aWidth%, aChoiceList$ ) : 118 DlgChoiceListZero%:( BYREF aChoice%, aPrompt$, aFlags&, aWidth%, aChoiceList$ ) : 119 DlgRadioButton%:( BYREF aRadio%, aPrompt$, aChoiceList$ ) : 120 DlgRadioButtonZero%:( BYREF aRadio%, aPrompt$, aChoiceList$ ) : 121 DlgCheckBox%:( BYREF aCheck%, aPrompt$ ) : 122 DlgComboBox%:(aStrAddr&, aPrompt$, aWidth%, aChoiceList$ ) : 123 REM : 124 REM : 125 DlgText%:( aPrompt$, aText$, aFlags%) : 126 DlgAnnotate%:( aPrompt$, aText$, aFlags%) : 127 DlgFile%:( aFilename&, aPrompt$, aFlags&) : 128 REM : 129 REM : 130 DlgChoiceString%:( aStrAddr&, aPrompt$, aFlags&, aWidth%, aChoiceList$ ) : 131 DlgChoiceStringZero%:( aStrAddr&, aPrompt$, aFlags&, aWidth%, aChoiceList$ ) : 132 DlgOnFocusLoss%:( aCallback$) : 200 DlgOnFocusChange%:( aCallback$) : 200 REM deprecated DlgOnValidate%:( aCallback$) : 201 DlgOnStateChange%:( aCallback$) : 202 DlgSetChoiceSeparator%:( aSeparator%) : 203 DlgPosition%:( aHPos%, aVPos%) : 204 DlgOnLoad%:( aCallback$) : 205 DlgOnFocusGain%:( aCallback$) : 206  DlgSetFocus%:( aLine%) : 250 DlgSetDimmed%:( aState%) : 251 DlgSetDimmedLine%:( aLine%, aState%) : 252 DlgSetVisible%:( aState%) : 253 DlgSetVisibleLine%:( aLine%, aState%) : 254 DlgSetWholeVisible%:( aState%) : 255 DlgSetWholeVisibleLine%:( aLine%, aState%) : 256 DlgActivateInGroup%:( aLine%) : 257 DlgSetTitle%:( aTitle$ ) : 258 REM DlgGetTitle$: : 259 DlgSetDimmedButton%:( aButtonID%, aState%) : 260 DlgGetFocus%: : 280 DlgIsDimmed%:( aLine% ) : 281 DlgIsVisible%:( aLine% ) : 282 DlgIsWholeVisible%:( aLine% ) : 283 DlgGetActiveInGroup%:( aLine% ) : 284 DlgIsDimmedButton%:( aButtonID%) : 285 DlgGetInt%:( aLine%) : 300 DlgGetLong&:( aLine%) : 301 DlgGetRangeLower%:( aLine%) : 302 DlgGetRangeUpper%:( aLine%) : 303 DlgGetRange%:( aLine%, BYREFaLower%, BYREF aUpper%) : 304 DlgGetRangeLongLower&:( aLine%) : 305 DlgGetRangeLongUpper&:( aLine%) : 306 DlgGetRangeLong%:( aLine%, BYREFaLower&, BYREF aUpper&) : 307 DlgGetFloat:( aLine%) : 308 DlgGetReal:( aLine% ) : 308 REM Synonym DlgGetChoice%:( aLine%) : 309 DlgGetRadio%:( aLine%) : 310 DlgGetCheckBox%:( aLine%) : 311 DlgGetComboBox$:( aLine% ) : 312 DlgGetDate&:( aLine%) : 313 DlgGetTime&:( aLine%) : 314 DlgGetText$:( aLine%) : 315 DlgGetCaption$:( aLine%) : 316 DlgGetTrailer$:( aLine%) : 317 DlgGetTextLabel$:( aLine%) : 318 DlgGetFile$:( aLine%) : 319 DlgGetChoiceString$:( aLine%) : 320 DlgGetBuffer&:( aLine%, aBufAddr&, aMaxLen&) : 321 DlgGetBufferSize&:( aLine%) : 322 DlgGetButtonText$:( aButtonID%) : 323 DlgSetInt%:( aLine%, aInt%) : 350 DlgSetLong%:( aLine%, aLong&) : 351 DlgSetRangeLower%:( aLine%, aLower%) : 352 DlgSetRangeUpper%:( aLine%, aUpper%) : 353 DlgSetRange%:( aLine%, aLower%, aUpper%) : 354 DlgSetRangeLongLower%:( aLine%, aLower&) : 355 DlgSetRangeLongUpper%:( aLine%, aUpper&) : 356 DlgSetRangeLong%:( aLine%, aLower&, aUpper&) : 357 DlgSetFloat%:( aLine%, aFloat) : 358 DlgSetReal%:( aLine%, aFloat) : 358 REM Synonym DlgSetChoice%:( aLine%, aChoice%) : 359 DlgSetRadio%:( aLine%, aRadio%) : 360 DlgSetCheckBox%:( aLine%, aCheckBox%) : 361 DlgSetComboBox%:( aLine%, aComboBox$) : 362 DlgSetDate%:(aLine%, aDate&) : 363 DlgSetTime%:(aLine%, aTime&) : 364 DlgSetText%:( aLine%, aString$) : 365 DlgSetCaption%:( aLine%, aString$) : 366 DlgSetTrailer%:( aLine%, aString$) : 367 DlgSetTextLabel%:( aLine%, aString$) : 368 DlgSetFile%:( aLine%, aFilename$) : 369 REM : 370 DlgSetBuffer%:( aLine%, aBufAddr& ) : 371 DlgSetButtonText%:( aButtonID%, aString$) : 372 DlgAddTrailer%:( aTrailer$) : 400 DlgEnableStateChange%: : 401 DlgDividerAfter%: : 402 DlgShowChoices%:( aLine%) : 500 DlgAppendChoiceList%:( aLine%) : 501 DlgReplaceChoiceList%:( aLine%) : 502 DlgChoiceListCount&:( aLine%) : 503 DlgSetComboBoxFromList%:( aLine%, anIndex&) : 504End DeclareREM -----------------------------------------------------------REM Definitions of callback functions. These don't exist in theREM OPX, but are what user-supplied functions should look likeREM when called by the OPX.REM OnValidate%:( aLine%, aKey&)REM aLine% The currently selected line number.REM aKey& Key code that triggered the validate call.REM RETURN% KTrue% if the dialog should not be closed.REM OnFocusChange%:( aLine%, aDirection%)REM aLine% Line number losing focus.REM aDirection% +ve = down; -ve=up.REM RETURN% KTrue% stops the focus-loss happening.REM OnStateChange%:( aLine%)REM aLine% Line number of control that has changed.REM RETURN% Ignored.REM OnLoad%:REM RETURN% Ignored.\ct1efd\c|1efd.A*Texted.app1 2y]ܱEPOC v nHO& |`^## # #######A-MP p#,00#`v @ # #v 04V # @ #v# |#Ѝp@-(M`$ P  - - - -00n#,@m#4 l#Ѝl(Ѝpp@-(M` P  - - - -0,S#,@R#U#4Ѝl(ЍpA-4MP0`@J#0A# $ @>#(@$ 1#06#04ЍE-pP@ `,#P `--0 Ѝ@ @-@ E$\#@#E-@Pp`@;$X0,0T080P000 D\ #<0\0xP00p`00ЀxЏA-p81,04180010Q|0S P`0U@\`"00T ""x!@Pxb#@\P0T"E%@\V%"""""P 0\"A#x0@-P0S c"@@"#0p@-@`P04S x"##0S`T 0p@"@-@t0  "t00   ͫ@-@t0 p"t@\ͫ0000@-M00 )#ЍA-MP0S Ȁx0S Q 0 x 04 P Q 0 04 0SdtlT\ `` ` ```000Q& x"4Ax"x"%x"pP @  " ^x"8 Q 0 04 Bx 0S 0|00S0)0|00S 0S`40s04000``0V@\p!00T !!: @`xЍA-P000pCU0!@`z"Py"Px"P`VPU@-p000PCU0!@`Z"PY"PX"P`VPE@-P`p0SP@T0 P" 0R@@Q 04 P Q 0 04  j"Q 04   M@-M  0R0S S S 0S &! 0 !!Ѝ@ ЍG-8Mp  /"@0,0T$("P`0P 0 04S00`V \0 !@t  0 0S    \  !!0000 0!@!P!@!(@,(0000 !D@!`@!P@!00-0-0-0-0 @ ЍP \00@( ! !@PP !`` !P !@@P ! 0P@-`--@-0 k ЍPR \_0\0@TU l!T@ p!DP l!HP m! h!P c!``P _! 0P`W!P@T!@@Q!00---`-0 @& ЍP \00@D '!0000 0  ꔞО 00 00h8ЍA-0Mp`P @@00 !@P# Q ! @00S M 0$ ЍPP 040Ѝp@-@`PU 000S 4 Rt00RQ  p@ 0@=C 0CS P pt4} 0S 0S R 40 pG-M00Y21 0S : Pp U$0Q@ T `/ P % P  P P `V QPPЍ@-0MPp0SSw0S0Sq 4@`v00t0SeV @dQ 04 `P QY 0V 04 TQ0S@@@ 0 @@t 0S 0S R @0 @0S 4 &00T @0 0S M 0$ ЍPP 040Ѝp@-M`@Px6@HDx4XEx0%x3PP @, x*8Ѝpp@-MP@t4y 0S 0S 0 R T% :$0T 0T:0  @yP`Cv00T Cn00T` Ѝp@-PM@00t80 0S XPYV0S 0 ePЍ@-MPp0S  Gm00`0S t@G 00S P`V xAx%x`P @  PxЍp@-MPQ xp%xv`P @H 3xmQ 0 0 ЍpG-P pxW`@@@ @0 }-- 0 0ЍA00t G-P px0`@@@ @0 -- 0 0ЍAx00th G- MP 4px `@@@ @,-0 -800-0 0ЍAK00tY; ЍG-MP(,px`@@@ @-0 -,V-- 0 l0ЍA00t+   ЍG-MP(,px`@@@ @-0 -,'-- 0 =0ЍA00t ЍG-MPx}` 7p 3@@@ @08 -8--0  0 ЍA00t ЍG-DMPxJ`8(@0<8  @  @@@ @ 0h -hpp--0 0 ЍAt00td DЍG-M0  700-00-0 K@7wЍЍ0@-@L P000 ]P@wͫ@-@7 PnA@ ͫ@-@( P_@ͫp@-M` PDPHDH P AͫЍp@-@P (5A@ͫ@-@P #@ͫ@-@0S0@@-MpPhXEXHDH `-0 +ЍAͫЍ@-MpP`~`{P @y-0 /ЍAoͫЍE-MPljp`fP@ Ta--0 0 ЍAIͫЍE-MaP/hFh+HDH.2p P'+p--P-0 0 ЍAͫЍE-M3Pjp` P @P--@-0 3 ЍAͫЍA-MpPd=`P @--0 =ЍAͫЍA-MPp`HDH P@$000@-@-0 BЍAͫЍG-MP~uHDH`x pt{Px@$000@P--`--@--- 0 DЍAXͫЍA-MP@oP8T AT 4@hͫ`-@x 1, =@ P 0T  W 00--`-0 K ЍAЍE-MP@.P8eT T @ͫ@x @h @ P  000---W00  ЍAЍG-M`@P8 T T @ͫ@ HDH PpU@DD#P =P  0:00---X00  ЍAЍG-MPPxurpi@e@ id u` @Pͫn0 00---0  ЍAIЍ0@-M@ P=A9Ѝ0A-MP@QP'@x` T  '@ P 0T - 00-p-0  ͫ- 00-p-0  ЍAЍ@-M`p PXDP @-0 ЍAͫЍ0@-MPP<# @ AͫЍ0p@-MPP @h  @ ;P 0T 80 V - ЍAͫЍpA-MpP`nHDH`q Pm@-0 4ЍAeͫЍp@-MP}P|Q` PK \@ P 0T 0 A;ͫЍp0@-MPSP, @(g%ͫЍ0@-@>Pui@ͫ@-@0Pg|@ͫ@-@@0S 0 A@0@-@0SlG@X@P0U A0@ͫ0@-MPP0# @ ͫЍ00@-MPP0  @ ͫЍ00@-MPP0 @ xͫЍ00@-MPP0 @| axͫЍ00@-MPP0 @e JaͫЍ0@-@MA\@Qp@-@`@@XV :@V  p@5p@-P@$@hT@ p@p@-P@@hT@ p@ @-@ A@ 0@-M@ P de; Ѝ0@-@A@ @-@Q  AP@  A@-@ AP@ @-@ AP@ @-@ AA@ @-@ AA@ @-@ A@k @-@y AA@| @-@l AA@o p@-M@m `j PX ( B(00C4000C40S Ѝp@-@A A@' @-@5 A@ A-M`: 7 p" ( B(0   Ѝ@-@ A @% @-@ AA@ @-Mp A`P P @u  @L  ; HЍ@-@ AA@ @-@ AA@ @-Mp A`P P_ @:  @   HЍ0@-M@ ( PB(njy Ѝ00@-M@ ( PB(\rg Ѝ0@-Mpr Am`P P @  @   HЍ@- M`W pT  e PP d @0  <  A@" Ѝ0@- M@ P0  '  A+ Ѝ0@-@ AD@5 @-@ AK@) @-@ AC@ @-@ A?@ 0@-BM@ ( PB(: Bߍ00@-@ XEX  A}0@ 0@-@ P  Ax0@ 0@-@ XEX  Ar0@ 0@-@ XEX  Ax0@ p@-` XEX HDH 0  0Avp@ 0@-@ P{  A90@~ 0@-@t Pk  A@0@n p@-@d `a PX 0  0A@p@X p@-@] `PD 0 A:p@F 0@-@6 XEX2  A60@5 0@-@% XEX!  A50@$ 0@-@ XEX  A/0@ 0@-M@ P   A) Ѝ00@-@ P  A60@ 0@-@ P  A|0@ 0@-@ P  AM0@ 0@-M@ P   At Ѝ00@-M@ P   Az Ѝ00@-M@ P   A} Ѝ00@-M@ P   Ak Ѝ00@-M@ Pz o  Aks Ѝ00@-M@ Pg \  Al` Ѝ0@-M`S  d pF HDH` P   B Ѝ@-@0 Aw@4 0@-@P#  A(0@& @-@ A@ @-@2 00,00ԟ@-@ N P @b @-@ 0@-@PX00P P 0 P 0X0@ ԟ0 R 00S040@-M@ P   APA Ѝ0A0QyH{L{}P{T{X{\{`{d{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}l{p{t{x{|{{{{{{{{{{{{{{{{||||}} |(|0|}}{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}4|<|@|H|L|D|8|}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}P|\|T|t|l||||||}d|}}}}}}}}}}}}}}}}}}}||||||}}}}}}}}}}}}}}||||||||||||||||||}}|} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }$}(},}0}4}8}<}@}D}L}P}T}X}\}`}d}}h}l}}}}}}}}}}}}}}}}}}}}}}}}}}}}p}t}x}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|}}}}H}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}h{]8Z$"d^(e r o  j51;97QOcav*5P\hGR]h!5t.>P_n}$1  ͫp@-M`@P HK%PP L @ ~rXЍp@Q0@-P|@P@rL0 @-@V@-5P@0@-@$00P0舠p@-P`L00@P 0p@pꈠ0@-PP0@Cv00@-@000A 000A0000@-M@ /0 000 0000 0   0ЍA-pH0 dPH0 PE 0HU``0@,P 00P 0(00 0V000P0  p@-`@D0 d@Dw0  p00>SPPU @d0  ppp@-P`$G@P 00P `Xp輟0@-@PX00E 00CS 50@꼟p@-P` ,BHT@T@P@`000p@-P`p ,BHT@T@VH0V000sP0f0p000ͫp@-@P`UH0U000XP00`000pͫp@-P@0 ,B``AP`@p@-`Pp@PPUP-PPp000G-Mp`0$tP@0 PP@ 0 P P @P0ЍA-M@P` 0?D]a;>?S$'cdf017M QRSTUVW\]_`abMPQUV[grvw}!+34DGJ8DlorEsv  %?Kw=AJSJfj$4!"L#U[^f&o1$Vgt -5?TCValidate callback failedNo number has been enteredInvalid dateInvalid timeInvalid time/dateFocusChange callback failedStateChange callback failedOnLoad callback failedName,Folder,DiskDlgDebugDebugInt failedAldurDlg؍|,8DjkD~8̓ؓ|( ĘИܘ $h$0<HH\Tl`lX~~HLVxzf  as'5=GPRXYZ[\ /08;BG.H89:;<>?D]a;>?S$'cdf017M QRSTUVW\]_`ab MPQUV[grvw}!+34DGJo8DlorEsv  %?Kw=AJSJfj$4!"L#U[^f&o1$Vgt -5?TC2EUSER[100000c1].DLLOPLR[10000077].DLLCONE[1000004d].DLLEIKON[100001c2].DLLBAFL[1000004e].DLLh H0000D0T0`0l0x00033333,50545@7D7H7L7P79<<<<<<<<0 000@05<88 @07777777777888 88888 8$8(8,80848884<0D8H8L8P8 9?? ?$??@0 00P >?`80L:;;;;;;;;;;;;;;;;;;;;;;<<< <<<<< <$<(<,<0<4<8<<<@>> >>>>> >$>(>,>0>4>8><>@>D>H>L>P>T>X>\>`>d>h>l>p>t>x>|>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??? ????? ?$?(?,?0?4?8?8>?t?2222222233 3t:x:|:::::::::::::::::::= >>>>>>>>>>? ??$?0?