Tag Archives: Controls

ListBoxes and TreeListBoxes – Checkbox Items

A recent question on the Revelation forum touched on the subject of using checkbox items in LISTBOX and TREELISTBOX controls, and this highlighted the need to document some of the new properties in OpenInsight v10 that support this functionality. In this post we’ll take a look at how you can use these to make adding checkbox items to your controls a simple task.

In previous versions of OpenInsight adding checkboxes to items was done with “smoke and mirrors”, i.e. actual item images were used to represent the checkbox, and the control itself had no concept of a checked state for any of it’s contents. Usually, when the user clicked on the item’s checkbox image, the UPDATE method was used toggle the image from checked to unchecked and vice versa. The checked state would be obtained by looking at the image number using the LIST property. Unfortunately this technique has two main drawbacks:

  • The code for detecting the mouse clicks can be complex, and when added to the image manipulation code itself the intent of the code can become obscured.
  • The images themselves must be maintained manually and updated to match the current Windows visual styling.

In OpenInsight v10 checkbox items are supported “natively” so that the control itself knows which items are “checked” and exposes the properties described below to support this. This results in less coding and a much cleaner program. 

The CHECKBOXES property

This is a simple boolean property that can be set in the Form Designer or at runtime. Setting it to TRUE$ ensures that all items in the control are drawn with a checkbox – this is all that needs to be done to use checkbox items.

The CHECKED property

This property allows you to get or set the checked state of one or more items using an @fm-delimited dynamic array of boolean flags.

// Set the second and fourth items in the LISTBOX to checked, ensure the
// third item is NOT checked.

CheckedItems = Get_Property( CtrlEntID, "CHECKED" )
CheckedItems<2> = TRUE$
CheckedItems<3> = FALSE$
CheckedItems<4> = TRUE$

Call Set_Property_Only( CtrlEntID, "CHECKED", CheckedItems )

The CHECKED property may also be used with the index parameter to get or set the state of a single item at a time:

// Set the ninth item to checked, and uncheck the tenth item
Call Set_Property_Only( CtrlEntID, "CHECKED", TRUE$, 9 )
Call Set_Property_Only( CtrlEntID, "CHECKED", FALSE$, 10 )

The CHECKEDX property

This property is similar to the CHECKED property but only applies to TREELISTBOX controls, and gets or sets the checked state for all items in the fully expanded list. 

CHECKEDLIST property

This property returns an @fm-delimited dynamic array of item indexes that have been checked. This is an optimization property so that you don’t have to iterate over the CHECKED property to find out what has been checked.

AllCheckedItems = Get_Property( CtrlEntID, "CHECKEDLIST" )

CheckedCount = FieldCount( AllCheckedItems, @Fm )
For N = 1 To CheckedCount
 CheckedItemNo = AllCheckedItems<N>
Next

CHECKEDLISTTEXT property

This property is similar to the CHECKEDLIST property except that it returns an @fm-delimited dynamic array of text for the checked items rather than their index.

AllCheckedItemsText = Get_Property( CtrlEntID, "CHECKEDLISTTEXT" )

CheckedCount = FieldCount( AllCheckedItemsText, @Fm )
For N = 1 To CheckedCount
 CheckedItemText = AllCheckedItemsText<N>
Next

Conclusion

So that wraps up this short post on checkbox items – hopefully you’ll find them much easier to use in your v10 applications.

Bonus Trivia

The CHECKED property name is a synonym for the original OpenInsight CHECK property name, and you may use either as it suits you – Here at Revelation we prefer to use CHECKED as it feels more natural. Note that this convention applies to other controls like the CHECKBOX control too.

WEBVIEW object documentation

First released with OpenInsight v10.2, the WEBVIEW object is a control that wraps the Microsoft WebView2 Edge Browser control and allows you to embed web technologies (HTML, CSS and JavaScript) in your OpenInsight forms.

This is just a quick post to let you know that the full documentation has been uploaded and can be found here:

   495 – WEBVIEW object.pdf

EditTables – The CELLPOSCHANGED event

OpenInsight 10.2 adds a new event called CELLPOSCHANGED to the EDITTABLE control. This is effectively the same as the normal POSCHANGED event but with the addition of an extra parameter called “ContextFlags” that provides more information on why the event was raised.

bForward = CELLPOSCHANGED( CtrlEntID,   |
                           CtrlClassID, |
                           NextColumn,  |
                           NextRow,     |
                           ContextFlags )

ContextFlags is a simple bitmask integer that contains the following flags:

Bit Flag ValueDescription
0x00000001If set then the cell position was changed via a keystroke.
0x00000002If set then the cell position was changed via the mouse.

Equates for these flags can be found in the PS_EDITTABLE_EQUATES insert record:

Equ PS_EDT_CTF_NONE$         To 0x00000000;
Equ PS_EDT_CTF_KEYSTROKE$    To 0x00000001;
Equ PS_EDT_CTF_MOUSECLICK$   To 0x00000002;

Example – testing to see if the position (CARETPOS) was changed via a mouse click:

$Insert PS_EditTable_Equates

If BitAnd( ContextFlags, PS_EDT_CTF_MOUSECLICK$ ) Then
   // CARETPOS was changed by using the mouse.
   ...
End

Notes on using the CELLPOSCHANGED event

  1. The default promoted system CELLPOSCHANGED event handler performs the same processing as the default promoted system POSCHANGED event handler (i.e. data validation and required checking etc).
  2. If a CELLPOSCHANGED event handler is defined by the developer then a standard POSCHANGED event will not be raised.
  3. To preserve backwards compatibility with existing applications the default promoted system CELLPOSCHANGED event will not be compiled into a control if there is no CELLPOSCHANGED quick event handler. This is to ensure that POSCHANGED is always executed if CELLPOSCHANGED has not been explicitly set for a control by the developer.
  4. CELLPOSCHANGED is available in OpenInsight 10.2 from the Beta 3 release onwards.

ListBoxes and TreeListBoxes – “in-place” editing

One of the new features that was added to the ListBox and TreeListBox controls in version 10 was the ability to use “in-place” editing on the items in the same manner as the Windows Explorer when you press “F2” or double-click an item. If you’ve done any work with the OpenInsight Menu Designers you will have seen this capability in action.

In-place editing for an item

The READONLY property

Enabling in-place editing is as simple as setting the READONLY property to False – once you’ve done that the user can press “F2” while using the control and edit the text of the currently selected item.  Pressing “Enter” when editing will update the item text (as will losing focus or selecting another item), while pressing “Esc” will abandon the changes.  Obviously that’s a very simple take on the topic and hardly worth a blog post in and of itself, so next we’ll take a look at some of the properties, methods and events that you can use to tailor the editing process.

The EDITING property

This is a simple boolean property that returns TRUE$ if an item is being edited.

The EDITORHANDLE property

This property returns the HANDLE of the editor control if an item is being edited.

The EDITKEY property

By default, hitting “F2” on an item puts the control into “edit mode”, just like the Windows Explorer.  However, if you wish to change this then you may use the EDITKEY property to select another key instead. The edit key is a Windows virtual key code and constants for these codes can be found in the MSWIN_VIRTUALKEY_EQUATES insert record.

The EDITOPTIONS property

This property allows you to fine-tune some of the validation options for the editor:

  • TextCase – Specifies if the text entered is lower-case only, upper-case only or mixed (See the EDITLINE TEXTCASE property for more details).
  • ValidChars – Specifies which characters may be entered into the editor (See the EDITLINE VALIDCHARS property for more details).
  • MaxLimit – Specifies the maximum number of characters that may be entered into the editor (See the EDITLINE LIMIT property for more details).

At runtime this property is an @fm-delimited array – constants for use with this property can be found in the PS_LISTBOX_EQUATES insert record.

The INCLUDEEDITORTEXT property

By default getting item text from the ListBox (e.g. via the LIST property) will include the text from an item currently being edited, even if that edited text has not yet been saved.  Setting this property to FALSE$ ensures that the returned item text ignores the value in the editor instead.

The BEGINEDIT method

This method allows you to programmatically put the ListBox into edit mode, as if the user had pressed “F2” (or whatever value the EDITKEY property is set to). You may specify the index of the item to edit, otherwise it will default to the current item.

RetVal = Exec_Method( CtrlEntID, "BEGINEDIT", itemIndex )

The ENDEDIT method

This method allows you to programmatically stop the item editing process, optionally allowing any changes to be accepted as if the “Enter” key had been pressed (the default is to reject any changes as if the “Esc” key had been pressed).

RetVal = Exec_Method( CtrlEntID, "ENDEDIT", bUpdate )

The ITEMEDITING event

This event is raised when an item it put into edit mode, and passes the index of the item as a parameter:

bForward = ITEMEDITING( CtrlEntID, CtrlClassID, ItemIndex )

The ITEMCHANGED event

This event is raised when the item is updated via the editor, i.e. the user hit the “Enter” key, the control lost the focus, or the EDITEDIT method was used with the bUpdate parameter set to TRUE$. The event passes the index of the item that has changed as well as the old and new data:

bForward = ITEMCHANGED( CtrlEntID, CtrlClassID, ItemIndex, |
                                                NewData,   |
                                                PrevData )

The ITEMUNCHANGED event

This event is raised when an item leaves edit mode without being updated, i.e. the user hit the “Esc” key or the EDITEDIT method was used with the bUpdate parameter set to FALSE$. The event passes the index of the item that was being edited:

bForward = ITEMUNCHANGED( CtrlEntID, CtrlClassID, ItemIndex )

So that wraps up this short post on ListBox editing – we’re sure that you’ll find many useful ways of implementing this new feature when expanding your application’s functionality.

The HTTPSERVER control

OpenInsight 10.2 introduces a new control type called HTTPSERVER, which provides a lightweight HTTP web-server control for use in your applications.

Using the control is a simple process:

  • Drop a “HTTP Server” control onto a form
  • Set the port number to listen on via the PORT property
  • Use the START method to start the server, or set the STARTUPMODE property to “Automatic” if you want the server to start when the form is created.
  • Listen for requests via the HTTPREQUEST event and respond to them using methods such as the SETRESPONSECONTENT and SETRESPONSEFILE methods
  • Return the response using the SENDRESPONSE method

So, if you set up a HTTPSERVER on port 8089 and execute the form you can use a browser to communicate with it via a URL something like this:

http://localhost:8089/path1/path2/test?arg1=this&arg2=that

The HTTPREQUEST event

As you can see, setting up the control is fairly easy, but the bulk of the work needs to be done in the HTTPREQUEST event where you examine the contents of the request and return the appropriate content.

The event has the following interface:

   bForward = HTTPREQUEST( CtrlEntID,     |
                           CtrlClassID,   |
                           RequestID,     |
                           RequestHeaders )

And the following parameters:

NameDESCRIPTION
CtrlEntIDID of the HTTP Server control firing the event
CtlrClassIDType of control firing the event – this is always “HTTPSERVER”
RequestIDUnique identifier for returning a response to the client – this is used with the various “SETRESPONSE” methods that set response data.
RequestHeadersAn @FM delimited dynamic array of data that describes the request. The format is similar to the HTTPRequest argument used in OECGI programming. The full format is described in the PS_HTTPSERVER_EQUATES insert record.

As mentioned above, the RequestHeaders parameter describes the details of the request using a format similar to the format used in OECGI programming. There are some differences that are worth highlighting however:

  • For a GET request the query values are already parsed into their own fields (<37> and <38>) as an associated multi-value pair. They are not found unparsed in field <1> as per OECGI.
  • For a POST or PUT request the content is obtained using the GETREQUESTCONTENT method (see below) – it is not passed in the RequestHeaders variable.
  • Cookies are already parsed into their own fields (<39> and <40>) as an associated multi-value pair.
  • Headers are already parsed into their own fields (<35> and <36>) as an associated multi-value pair.

Note that out of the box we do not enforce any restrictions or framework on how you handle the request – compare this to classic OECGI programming where the “PathInfo” field is used to determine which “INET_” procedure is executed to fulfill it (via the RUN_INET_REQUEST stored procedure) There is no such requirement with the HTTPSERVER control, and you may create your own framework if you wish (although see the note on RTI_RUN_HTTPSERVER_REQUEST below).

Returning a response

There are several methods described below that you may use to process the content that you return to the client.

  • GETREQUESTCONTENT
  • GETRESPONSECONTENT
  • GETRESPONSECOOKIE
  • GETRESPONSEFILE
  • GETRESPONSEHEADER
  • GETRESPONSESTATUS
  • ISPORTINUSE
  • SETRESPONSECONTENT
  • SETRESPONSECOOKIE
  • SETRESPONSEFILE
  • SETRESPONSEHEADER
  • SETRESPONSESTATUS
  • SENDRESPONSE

Note: With each of these you must use the unique RequestID parameter passed to you in the HTTPREQUEST event.

E.g. Returning HTML in the HTTPREQUEST event

ReposID = @AppID<1> : "*DOC*HTML*INDEX_PAGE" 
HTML = Repository( "ACCESS", ReposID )
Call Exec_Method( CtrlEntID, "SETRESPONSECONTENT", RequestID, HTML )
Call Exec_Method( CtrlEntID, "SENDRESPONSE" )

E.g. Returning a file in the HTTPREQUEST event

ReposID = @AppID<1> : "*DOC*HTML*INDEX_PAGE" 
FilePath = Repository( "GETSUBKEY", ReposID )
Call Exec_Method( CtrlEntID, "SETRESPONSEFILE", RequestID, FilePath )
Call Exec_Method( CtrlEntID, "SENDRESPONSE" )

The HTTPSERVER methods

GETREQUESTCONTENT method

Gets the raw content sent to the server by the client as part of a POST or PUT request.

 ReqContent = Exec_Method( CtrlEntID, "GETREQUESTCONTENT", RequestID )

GETRESPONSECONTENT method

Returns raw content for the response as set via a previous call to the SETRESPONSECONTENT method.

 RspContent= Exec_Method( CtrlEntID, "GETRESPONSECONTENT", RequestID )

GETRESPONSECOOKIE method

Returns details for a response cookie as set via a previous call to the SETRESPONSECOOKIE method (see below for the CookieVal format).

 CookieVal = Exec_Method( CtrlEntID, "GETRESPONSECOOKIE", RequestID, |
                                                          CookieName )

GETRESPONSEFILE method

Returns the name and path of the response content file set with a previous call to the SETRESPONSEFILE method.

 RspFile = Exec_Method( CtrlEntID, "GETRESPONSEFILE", RequestID )

GETRESPONSEHEADER method

Returns the details for a response header as set via a previous call to the SETRESPONSEHEADER method.

 HeaderVal = Exec_Method( CtrlEntID, "GETRESPONSEHEADER", RequestID, |
                                                          HeaderName )

GETRESPONSESTATUS method

Returns the HTTP status code of the response (defaults to 200).

 RspStatus = Exec_Method( CtrlEntID, "GETRESPONSESTATUS", RequestID )

ISPORTINUSE method

Returns TRUE$ if the specified port is in use on the local machine.

 InUse = Exec_Method( CtrlEntID, "ISPORTINUSE", Port, IPv6 )
  • Port – Identifies the port to check
  • IPv6 – if TRUE$ then check the IPv6 bindings, otherwise check the IPv4 bindings

SENDRESPONSE method

Sends the response back to the client. This method should be called when you have finished setting the response details (Note that this is called by the promoted system HTTPREQUEST handler in case you forgot to do it in your own code!).

 RspSent = Exec_Method( CtrlEntID, "SENDRESPONSE", RequestID )

SETRESPONSECONTENT method

Sets the content to return to the client, such as a string containing an HTML page.

 SetOK= Exec_Method( CtrlEntID, "SETRESPONSECONTENT", RequestID, |
                                                      Content )

SETRESPONSECOOKIE method

Sets a cookie that is returned to the client via the “Set-Cookie” header.

 SetOK = Exec_Method( CtrlEntID, "SETRESPONSECOOKIE", RequestID,  |
                                                      CookieName, |
                                                      CookieValue )

CookieValue is an @fm-delimited array formatted as follows:

    <1> Value
    <2> Path
    <3> Domain
    <4> Expires (internal date format)
    <5> Max Age (seconds)
    <6> Secure  (TRUE$/FALSE$)
    <7> HttpOnly (TRUE$/FALSE$)
    <8> SameSite

SETRESPONSEFILE method

If you have a file that contains the content you wish to return then you should use this method to let the server read the file and return it to the client itself. This offers better performance than reading the contents via Basic+ and using the SETRESPONSECONTENT method as it avoids any unnecessary copying of data.

 SetOK = Exec_Method( CtrlEntID, "SETRESPONSEFILE", RequestID,  |
                                                    FileNamePath )

SETRESPONSEHEADER method

Sets a response header and value to be returned to the client.

 SetOK = Exec_Method( CtrlEntID, "SETRESPONSEHEADER", RequestID,  |
                                                      HeaderName, |
                                                      HeaderValue )

SETRESPONSESTATUS method

Sets the HTTP status code for the response (200, 404, 500 etc).

 SetOK = Exec_Method( CtrlEntID, "SETRESPONSESTATUS", RequestID, |
                                                      StatusCode )

Example HTTPREQUEST handler

As part of version 10.2 we have included a sample HTTPREQUEST event handler called RTI_RUN_HTTPSERVER_REQUEST which you can examine and copy for your own applications if you wish. It emulates the core behavior of the OECGI RUN_INET_REQUEST handler in that it uses the “PathInfo” field to determine the stored procedure to fulfill the request. In this case it looks for a matching procedure that has the prefix “HTTPSVR_” and we have included a couple of example “HTTPSVR_” procedures for you to review as well.

Conclusion

With the addition of the HTTPSERVER control it is now possible to provide HTML content directly from your application, and also provide a means of web-development directly from your desktop without necessarily needing to install a dedicated web-server like IIS.

It is also a good solution for when you want to provide local HTML content in your application’s user-interface via an embedded browser control, because it can avoid the usual security restrictions that browsers enforce for such scenarios.

The DIRWATCHER control

With the release of version 10.1 a new control type called DIRWATCHER (“Directory Watcher”) has been added to OpenInsight. This is a fairly simple control which allows you to monitor one or more directories on your system and then receive notifications when the contents are changed.

Using the control is very straightforward:

  • Use the WATCHDIR method to add a directory to monitor for changes.
  • Handle the CHANGED event to receive notifications of directory changes.
  • Use the STOP method to stop monitoring directories.

We’ll take a quick look at each of these methods and events below along with a couple of important properties:

The WATCHDIR method

This method allows you to specify a directory to monitor along with some optional flags. It may be called multiple times to watch more than one directory.

bSuccess = Exec_Method( CtrlEntID, "WATCHDIR", DirName, bSubtree, Flags )
ParameterDescription
DirName(required) Specifies the name of the directory to watch. It should be a fully qualified, non-relative directory path.
bSubtree(optional) Set to TRUE$ to monitor all sub-directories beneath DirName as well. Defaults to FALSE$.
Flags(optional) A bit-mask value containing a set of flags that denote the events to monitor in the directories. It defaults to the following flags:

FILE_NOTIFY_CHANGE_FILE_NAME$
FILE_NOTIFY_CHANGE_LAST_WRITE$
FILE_NOTIFY_CHANGE_CREATION$

The flag values are specified in the MSWIN_FILENOTIFY_EQUATES insert record,

This method returns TRUE$ if successful, or FALSE$ otherwise.

The STOP method

This method stops the control monitoring its specified directories.

bSuccess = Exec_Method( CtrlEntID, "STOP" )

This method returns TRUE$ if successful, or FALSE$ otherwise.

(Note – to resume directory monitoring after the STOP method has been called the WATCHDIR method(s) must be executed again).

The CHANGED event

This event is raised when changes have been detected in the monitored directories.

bForward = CHANGED( NewData )

This event passes a single parameter called NewData which contains an @vm-delimited list of changed items (i.e. notifications). Each item in the list comprises an “action code” and the name and path of the affected file, delimited by an @svm.

Action codes are defined in the MSWIN_FILENOTIFY_EQUATES insert record like so:

   equ FILE_ACTION_ADDED$               to 0x00000001   
   equ FILE_ACTION_REMOVED$             to 0x00000002   
   equ FILE_ACTION_MODIFIED$            to 0x00000003   
   equ FILE_ACTION_RENAMED_OLD_NAME$    to 0x00000004   
   equ FILE_ACTION_RENAMED_NEW_NAME$    to 0x00000005 

Remarks

If a monitored directory experiences a high volume of changes (such as copying or removing thousands of files) it could generate a correspondingly high number of CHANGED events, which in turn could produce an adverse affect on your application and slow it down. In order to deal with this potential issue it is possible to “bundle up” multiple notifications with the NOTIFYTHRESHOLD property into a single CHANGED event so they may be processed more efficiently.

The NOTIFYTHRESHOLD property

The NOTIFYTHRESHOLD property is an integer that specifies the maximum number of notifications that should be bundled before a CHANGED event is raised.

CurrVal = Get_Property( CtrlEntID, "NOTIFYTHRESHOLD" )
PrevVal = Set_Property( CtrlEntID, "NOTIFYTHRESHOLD", NewVal )

By default it is set to 100.

The NOTIFYTIMER property

The NOTIFYTIMER property is an integer that specifies the number of milliseconds before a CHANGED event is raised if the NOTIFYTHRESHOLD property value is not met.

CurrVal = Get_Property( CtrlEntID, "NOTIFYTIMER" )
PrevVal = Set_Property( CtrlEntID, "NOTIFYTIMER", NewVal )

By default it is set to 50 (ms).

Remarks

If the NOTIFYTHRESHOLD property is set to a value greater than 1 then the control will try to bundle that number of notifications together before raising a CHANGED event. However, when this is set to a high value it is possible that the threshold may not be reached in a timely fashion and the CHANGED event not actually raised.

E.g. If the NOTIFYTHRESHOLD is set to 1000, and only 200 notifications are received then the CHANGED event would not be raised.

To prevent this problem the NOTIFYTIMER property may be used to specify the amount of time after receiving the last notification before a CHANGED event is raised even if the NOTIFYTHRESHOLD is not met.

E.g. in the example above, if the control had a NOTIFYTIMER of 50, then a CHANGED event would be raised 50ms after the last notification (200) was received, even though the NOTIFYTHRESHOLD of 1000 has not actually been met.

Developer Notes

The DIRWATCHER control is intended as a “non-visual” control and should probably be hidden at runtime in your own applications. However, it is actually derived from a normal STATIC control so all of the properties and methods that apply to a STATIC apply to the DIRWATCHER as well, and you may use them as normal if you wish.

Reordering tabs with the AllowDragReorder property

The next release of OpenInsight includes a new TABCONTROL property called ALLOWDRAGREORDER, which allows you to drag a tab to a new position within the control. It’s a simple boolean property, and when set to True tabs may be dragged and reordered with the mouse – an image of the tab is moved with the cursor, and a pair of arrows are displayed to mark the potential insertion point.

Here’s an example of a tab being dragged in the IDE:

Shows a image of the IDE with a tab being dragged by a cursor, along with the drag0image and the insertion marker arrows.

Bonus trivia

  • The tabs may be scrolled while dragging by hovering outside either edge of the control.
  • This property is not supported for:
    • MultiLine tab controls
    • Vertically-aligned tab controls
  • The LISTBOX control also supports this property for reordering its items – see the “Order Tabs” dialog in the Form Designer for an example, or the list of types in the IDE’s “Open Entity” dialog.

Screenshots with the CAPTUREIMAGE method

Bitmap controls in OpenInsight 10 have a method called CAPTUREIMAGE, which allows you to “screenshot” the contents of another OI control or form into the Bitmap control’s IMAGE sub-object. As you can see, it has a very simple interface:

SuccessFlag = Exec_Method( BitMapCtrlID, "CAPTUREIMAGE", CaptureID )

Where “CaptureID” is the fully qualified name of the control to screenshot.

E.g.

If we have a form called TEST_CAPTUREIMAGE, with a BITMAP control called BMP_SCREENSHOT, then we can screenshot the contents of the IDE into it like so:

Call Exec_Method( "TEST_CAPTUREIMAGE.BMP_SCREENSHOT", "CAPTUREIMAGE", |
                   "RTI_IDE" )
Shows a captured image of the OpenInsight IDE in a Bitmap control.

(N.B. The captured image you see displayed above is scaled – the screenshot is stored at full resolution in the control itself)

One obvious use for this is for support purposes, e.g:

  • Take a screen-shot with CAPTUREIMAGE.
  • Use The SAVETOFILE method in the IMAGE API to save it to a file.
  • Create an email message with the image file attached or embedded and send it to your support desk.

We’re sure you can think of more.

Bonus trivia:

  • CAPTUREIMAGE works with any object that supports the Windows WM_PRINTCLIENT message.
  • BITMAP controls are basically an alias for STATIC controls, so all STATIC controls support this method.

Context Menu updates

The next release of OpenInsight sees a few updates to context menus and the ContextMenu Designer, so in this post we’ll take a brief look at these upcoming changes.

Moving the focus

One important aspect of standard Windows context menu behavior is that the focus is moved (if possible) to the control that the menu belongs to. Current versions of OpenInsight do not follow this pattern so the next release includes a fix for this, and this is something you should be aware of just in case it impacts your application (though to be honest, we’re not really expecting it to!).

Test-Run support

The Context-Menu Designer now supports the IDE “Test-Run” feature, so that you can see how your context menu will appear when you use it in your application.

When you test-run your context menu you will see a simple dialog box with an edit control (EDL_TEST) and and a static control (TXT_TEST) like so:

Test-run context menu dialog box

Right-clicking either of these controls displays your context menu:

Selecting an item displays it’s fully-qualified name, which has the standard format of:

<windowName> "." <controlName> ".CONTEXTMENU." <itemName>

So, for the test run dialog, it will be one of the following:

"RTI_DSN_CONTEXTMENU_TESTRUN.EDL_TEST.CONTEXTMENU." <itemName>
"RTI_DSN_CONTEXTMENU_TESTRUN.TXT_TEST.CONTEXTMENU." <itemName>

E.g.

Message box showing the name of the menu item that was clicked

Common menu support

The initial release of the ContextMenu Designer in v10.0.8 included check-boxes for two “common menu” options as shown in the screenshot below. Each of these options appends a set of standard menu items to your context menu, and both have been enhanced for the next release and include new artwork as well.

Shows the Content Menu designer with the  "Include OI Menu" and "Include Windows Menu" check-boxes highlighted.

The “OI Menu” appends the following items:

  • Options – Display options for the current control.
  • Help – Display help for the current control.
  • Data Binding – Display data-binding information for the current control.

Whilst the “Windows Menu” appends the following standard “Edit” items instead:

  • Undo
  • Cut
  • Copy
  • Paste
  • Delete
  • Select All

In both cases the default system CONTEXTMENU event (i.e. the event responsible for actually displaying the menu) synchronizes the items to the parent control by using the HELPFLAGS and EDITSTATEFLAGS properties respectively.

(The definition for these items can be found in the SYSPROG “OIMENU_” and “WINMENU_” ContextMenu entities respectively – you may adjust these if you wish, but be aware that they may be overwritten in future OpenInsight updates, so you should make copies in your own application).

The @MENUPARENT pseudo-control name

When using QuickEvents there are several pseudo-control names you can use, such as “@WINDOW”, “@FOCUS” and “@SELF”, that are resolved to a “real” control name at runtime.

However, in order to be able to reference the context menu’s parent control at runtime we’ve introduced a new pseudo-control name called “@MENUPARENT”. This resolves to the name of the control displaying the menu and should be used in place of “@FOCUS” because it is perfectly possible for controls that don’t accept the focus (like Static Text controls) to have a context menu, and @FOCUS would not resolve to the correct value. Note that @MENUPARENT can only be used with MENU QuickEvents for context menu items – it cannot be used with any other type or event.

Shows the @MENUPARENT pseudo-control name being used for a menu QuickEvent

Context menus are an essential part of modern user interface design and we encourage you to use them as much as possible in your own applications – hopefully you’ll find that the tools provided in OpenInsight 10 make this easy to achieve!

The SHOWDATABINDING method

In the next release of OpenInsight we’ve added a new feature that allows you to quickly display runtime databinding information for the controls in your application – the aptly named SHOWDATABINDING method.

It’s a simple method that is supported by all controls, and can be invoked like so:

Call Exec_Method( CtrlEntID, "SHOWDATABINDING" )

If the control is bound to a database table then it displays a view-only dialog of data binding information for that control. The following example shows the information for a bound column in an EditTable control:

Dialog box showing an example of the databinding information displayed via the SHOWDATABINDING method.

The Description, Validation, Heading and Formula attributes all have their own sub-dialog boxes to display their full details.

If the control is not databound a simple message is displayed to inform the user of the fact.

This method can easily be added to menu or contextmenu QuickEvents in your own applications if you wish to expose this information to your users, or just for your own diagnostic purposes.