Tag Archives: Properties

OLE Control improvements in v10.0.8

We added quite a bit of design-time functionality for OLE controls in v10.0.8 so this post provides a quick overview of what’s new:

The CLSID property

This property has a new “editor” dialog.  While it doesn’t allow you to change the CLSID (that’s by design – if you change the CLSID it’s a totally different control!) it does provide you with a lot of information about the control question such as it’s Registry attributes and it’s properties, methods and events, e.g:

OLE Control CLSID General Tab

OLE Control CLSID Properties Tab

OLE Control CLSID Methods Tab

OLE Control CLSID Events Tab

The QualifiedOleEvents property

This property has a new editor that allows you to specify which OLE events you wish to qualify when the control is created, hopefully removing the need for you to do this in code:

OLE Control QualifiedOleEvents Editor

The OLE Properties section

We’ve also added a new category called “OLE” to the properties displayed in the IDE Property Panel, and this contains all of the design-time OLE properties that can be edited for the control:

OLE Properties in the IDE Property Panel

You may also notice that we’ve added some property type-support for editing OLE properties here as well:

  • Color properties can now use the standard Color property editor
  • Fonts can now be edited with the standard Windows Font dialog
  • Enumerated types are edited with a dropdown list showing the “internal” and “external values, e.g:

OLE Enumerated Properties dropdown

Hopefully this will make working with OLE controls and OpenInsight 10 easier for you in the future.

Adding Custom Properties in the Form Designer

User-defined properties (“UDPs”) have always been supported at run-time in OpenInsight by giving the desired property a name prefixed with an “@” symbol and then setting a value for it, e.g:

Call Set_Property( CtrlEntID, "@MYPROP_1", "SomeVal" )
Call Set_Property( CtrlEntID, "@MYPROP_2", "SomethingElse" )

Value = Get_Property( CtrlEntID, "@MYPROP_1" )

// etc...

With the upcoming release of version 10.0.8, design-time support for these has been added in the Form Designer via the new “CustomProperties” property.  This is simply a list of UDP  property names and values that can be specified and stored in the Form definition record, which are then processed during form creation to create UDPs that can be accessed in the normal way by Get_Property and Set_Property.

For example, if you enter a couple of custom properties in the Form Designer called MYPROP_1 and MYPROP_2:

CustomProperties Property

Editing the CustomProperties property

You may then use these with Get_Property and Set_Property at runtime, by referencing them with an “@” prefix (i.e. “@MYPROP_1” and “@MYPROP_2”) like so:

// Value will contain "SomethingElse"
Value = Get_Property( CtrlEntID, "@MYPROP_2" )

Two things to note:

1) You don’t need to specify an “@” prefix for the property name in the CustomProperties editor, and

2) You are not limited to simple strings when entering CustomProperties values – you may also use the standard “[,]” syntax for entering dynamic arrays just like you would for QuickEvent parameters:

E.g. to enter an @fm-delimited array you enclose the list of items in ‘[]’ brackets, and delimit them with a comma like so:

An array like this: 

   <1> ItemOne
   <2> ItemTwo

Can be entered as:

   ['ItemOne','ItemTwo']

Note that each array item must be single-quoted, but you can escape a quote in the data by using two single quotes, e.g.

An array like 

   <1> ItemOne
   <2> ItemTwo's Stuff

Can be entered as:

   ['ItemOne','ItemTwo''s Stuff']

For arrays with lower-level delimiters like @vm and @svm you add a set of nested ”[]’ brackets for each level, e.g:

An array like:
   <1>      ItemOne
   <2,1>    ItemTwo_A
   <2,2>    ItemTwo_B
   <2,3,1>  ItemTwo_C_1
   <2,3,2>  ItemTwo_C_2
   <3>      ItemThree

Can be entered as:
   
   ['ItemOne',['ItemTwoA','ItemTwoB',['ItemTwo_C_1','ItemTwo_C_2']],'ItemThree']

And so on.

Hopefully you find this new feature useful and help to reduce the amount of code you need to write.

A focus on the FOCUS property

There are two methods for setting the input focus in OpenInsight, and there is a subtle implementation difference that can impact your applications if you’re not careful how you apply them.

The first method is to use an object’s own FOCUS property and set it to TRUE$ like so:

Call Set_Property_Only( @Window : ".EDL_SURNAME", "FOCUS", TRUE$ )

This moves the focus to the specified object, but the event queue will be flushed both before and after the focus has been set, thereby preventing any events raised as a result of the focus being moved from being processed.  This method was originally designed for use with validation routines so the focus could be reset to an invalid control “safely”.

The second method is to use the SYSTEM object’s FOCUS property:

Call Set_Property_Only( "SYSTEM", "FOCUS", @Window : ".EDL_SURNAME" )

This moves the focus, but any events triggered as a result of moving the focus (like LOSTFOCUS and GOTFOCUS events) will be processed.

That all sounds straightforward enough, but using the first method can lead to unexpected results if you are relying on an event already in the queue that you subsequently need – not a common situation but one we encountered recently while converting an old form to v10.  In our case we had a menu failing to show when the focus was on a specific control, and it turned out that the LOSTFOCUS event for the control was setting it’s FOCUS property to TRUE$.  This had the effect of killing a pending MENUDROPDOWN event (new in v10) that created the menu to display, hence no menu.

In this case the solution is to use the SYSTEM BLOCKEVENTS property to turn off events being triggered while the focus is moved and then restore event processing afterwards:

Call Set_Property_Only( "SYSTEM", "BLOCKEVENTS", TRUE$ )
Call Set_Property_Only( "SYSTEM", "FOCUS", @Window : ".EDL_SURNAME" )
Call Set_Property_Only( "SYSTEM", "BLOCKEVENTS", FALSE$ )

This prevented any LOSTFOCUS and GOTFOCUS events from being raised, but the MENUDROPDOWN event was still in the queue.

Using the SYSTEM FOCUS and BLOCKEVENTS properties in this way is a far “safer” alternative when moving the focus because you have full control over how events are handled, and I would always advocate using this method over using a control’s own FOCUS property.

 

Coloring your tabs with the ITEMSTYLE property

A new facility introduced in version 10 is the ability to set the styling information for the tabs in the TabControl using the new ITEMSTYLE and ITEMSTYLES properties, and in this post we’ll explain how to use them.

TabStates and ItemStyles

Each tab in a TabControl can be in one of the following states at runtime:

  • Normal (Unselected tab)
  • Hot (Mouse is over a Normal tab)
  • Disabled
  • Selected
  • Hot Selected (Mouse is over the selected tab)

And for each one of these states you can specify the following styling information for the tabs:

  • ForeColor
  • BackColorFrom
  • BackColorTo
  • Bold
  • Italic
  • Underline
  • Translucency
  • CloseButton ForeColor
  • CloseButton BackColor

To do this at run-time you can use one of the following properties:

  • The ITEMSTYLE property
  • The ITEMSTYLES property

and we’ll take a look at each of these in turn.

 

The ITEMSTYLE property

   prevStyle = Get_Property( ctrlEntID, "ITEMSTYLE", itemState )
   currStyle = Set_Property( ctrlEntID, "ITEMSTYLE", newStyle, itemState )

This property allows you to get or set the ITEMSTYLE for a single state.  The property itself is an @fm-delimited array of styling information like so:

    <1> ForeColor             (COLORREF)
    <2> BackColor From        (COLORREF)
    <3> BackColor To          (COLORREF)
    <4> Bold                  (1/0)
    <5> Italic                (1/0)
    <6> Underline             (1/0)
    <7> Translucency          (0-100)
    <8> CloseButton ForeColor (COLORREF)
    <9> CloseButton BackColor (COLORREF)

Equates for these array positions can be found in the PS_TABCONTROL_EQUATES insert record:

   equ TCIS_POS_FORECOLOR$           to 1 ; * // COLORREF
   equ TCIS_POS_BACKCOLOR_FROM$      to 2 ; * // COLORREF
   equ TCIS_POS_BACKCOLOR_TO$        to 3 ; * // COLORREF
   equ TCIS_POS_BOLD$                to 4 ; * // Boolean
   equ TCIS_POS_ITALIC$              to 5 ; * // Boolean
   equ TCIS_POS_UNDERLINE$           to 6 ; * // Boolean
   equ TCIS_POS_TRANSLUCENCY$        to 7 ; * // UInt (0-100)
   equ TCIS_POS_CLOSEBTNFORECOLOR$   to 8 ; * // COLORREF
   equ TCIS_POS_CLOSEBTNBACKCOLOR$   to 9 ; * // COLORREF

You must also use the index parameter with the Get_Property and Set_Property to specify the tab state that you are setting, which is an integer between 1 and 5:

   equ TCIS_NORMAL$                   to 1
   equ TCIS_HOT$                      to 2
   equ TCIS_DISABLED$                 to 3
   equ TCIS_SELECTED$                 to 4
   equ TCIS_HOTSELECTED$              to 5

Example: Setting the Hot and Hot Selected styles

   $insert colors
   $insert logical

   // Set the mouseover text to change to red 
   itemStyle = ""
   itemStyle<TCIS_POS_FORECOLOR$> = RED$
   
   Call Set_Property_Only( ctrlEntID, "ITEMSTYLE", |
                           itemStyle,              |
                           TCIS_HOT$ )

   // Set the mouseover text for a selected item to change to red
   // and bold
   itemStyle = ""
   itemStyle<TCIS_POS_FORECOLOR$> = RED$
   itemStyle<TCIS_POS_BOLD$>      = TRUE$
   
   Call Set_Property_Only( ctrlEntID, "ITEMSTYLE", |
                           itemStyle,              |
                           TCIS_HOTSELECTED$ )

 

The ITEMSTYLES property

   prevStyles = Get_Property( ctrlEntID, "ITEMSTYLES" ) 
   currStyles = Set_Property( ctrlEntID, "ITEMSTYLES", newStyles )

This property is very similar to the ITEMSTYLE property except that it allows you to get or set the styles for all states at once.

The property itself is an @fm/@vm delimited array: each state is delimited by @fm, and the styling information for each state is delimited by @vm.

   <1> ItemStyle for the Normal State
   <2> ItemStyle for the Hot State
   <3> ItemStyle for the Disabled State
   <4> ItemStyle for the Selected State
   <5> ItemStyle for the Hot Selected State

(You will note these map onto the “TCIS_” state equates shown above)

For each one of these states the ItemStyle information is an @vm delimited array using the same structure as for the ITEMSTYLE property, i.e:

   <0,1> ForeColor             (COLORREF)
   <0,2> BackColor From        (COLORREF) 
   <0,3> BackColor To          (COLORREF) 
   <0,4> Bold                  (1/0) 
   <0,5> Italic                (1/0) 
   <0,6> Underline             (1/0) 
   <0,7> Translucency          (0-100) 
   <0,8> CloseButton ForeColor (COLORREF) 
   <0,9> CloseButton BackColor (COLORREF)

So you can use the “TCIS_POS_” equates shown above as well.

Example: Setting the Hot and Hot Selected styles using ITEMSTYLES

   $insert colors
   $insert logical

   itemStyles = Get_Property( ctrlEntID, "ITEMSTYLES" )

   // Set the mouseover text to change to red 
   itemStyles<TCIS_HOT$, TCIS_POS_FORECOLOR$> = RED$
   
   // Set the mouseover text for a selected item to change to red 
   // and bold
   itemStyles<TCIS_HOTSELECTED$,TCIS_POS_FORECOLOR$> = RED$
   itemStyles<TCIS_HOTSELECTED$,TCIS_POS_BOLD$>      = TRUE$
   
   Call Set_Property_Only( ctrlEntID, "ITEMSTYLES", itemStyles )

 

Setting ItemStyles in the Form Designer

Item styling for the tab control can also be specified at design time by using the “ItemStyles” property that is available when you select the tab control in the form designer.  When you click the button for this property you will see an ItemStyles editor dialog that lets you specify the styling information:

TabControl ItemStyles Editor

(Note that in the current release (10.0.6) you will not see this applied to the design control – this will be fixed in an upcoming release)

Tracking the SAVEWARN property

As veteran OpenInsight programmers know, the system uses a simple boolean flag (exposed as the SAVEWARN property) to determine if the contents of a data-bound form have changed.  This flag can be updated in several ways, the most common being:

  • From the LOSTFOCUS event of a control.
  • From the POSCHANGED, INSERTROW and DELETEROW events of an EDITTABLE control.
  • From setting a control’s DEFPROP property.
  • From the CLOSE event of a form when the control with focus is inspected to see if it has changed.

It is checked during the CLEAR and CLOSE events to see if it has been set and an “Unsaved Changes” warning issued to the user if so.  Most of the time this system works quite well, but (as anyone who has spent several years working with OI systems knows) sometimes it gets triggered when you least expect it, and you’re left with no clue as to why.

To help with this situation the next version of OpenInsight introduces SAVEWARN tracking, so you can see which parts of the system update the SAVEWARN property and when they actually do it. In previous versions the system updated the SAVEWARN flag directly (it’s a simple variable in the “window common area”) but this has been changed to use the Set_Property function so it can be monitored effectively from a single point.

To track SAVEWARN you have two choices:

  • Use the SYSMSG event
  • Use the System Monitor

 

Using the SYSMSG event to track SAVEWARN

Every time SAVEWARN is set a standard SYSMSG event is raised with a SAVEWARNINFO code; the system itself does nothing with this message, but it’s there for you to use if you wish.  This option is probably more suited for run-time tracing as it’s something you could add to your applications easily if you needed to.

The PS_EQUATES insert record defines the SAVEWARNINFO message number that you can intercept:

equ SYSMSG_SAVEWARNINFO$ to 21  ; // Save warn has been changed - null msg

The Auxiliary parameter passed to the  SYSMSG event contains information that describes why the SAVEWARN property was changed.

 

Using the System Monitor to track SAVEWARN

The SetDebugger() function has been updated to support a new method called “SAVEWARN” that enables SAVEWARN tracking so that changes are displayed in the System Monitor.  This option is probably more suited to development use rather than run-time.

From the System Monitor execute:

setdebugger savewarn 1

to turn on tracing, and:

setdebugger savewarn 0

to turn it off.

E.g:

SAVEWARN tracing in the System Monitor

SAVEWARN tracing in the System Monitor

Setting the SAVEWARN property

If you wish to set SAVEWARN yourself you may use the “index” parameter to pass a description for the change, so this can be picked up in any tracing scenario like so:

Call Set_Property_Only( @Window, "SAVEWARN", TRUE$, "From My Stuff" )

This description is then passed in the Auxiliary parameter of the  SYSMSG event as noted above.

 

Hopefully you will find this facility useful if you ever suffer from problems with SAVEWARN in the future.

EditTables – The Sub-Object Interface

One of the changes we wanted to make with EditTables in v10 was to expose all of their runtime functionality easily through the normal property/method API.  Some of this was already available in previous versions, but usually involved a method to set a plethora of style bits, which is not really satisfactory unless you’re a C++ programmer (as we have been reminded by various developers on several occasions!).

Besides the EditTable as a whole, there are essentially three other main programmable areas:

  1. Columns
  2. Rows
  3. Cells

Providing unique properties and methods to address the capabilities of these areas is not really practicable, as it leads to an “explosion” of property names: For example, accessing the “text” associated with each of these would require three new properties such as:

  • COLUMNTEXT
  • ROWTEXT
  • CELLTEXT

Of course that’s only three, but considering that each of the aforementioned areas has something like 30 properties, you would suddenly add 90+ new property names to the product!  Bear in mind also that columns, rows and cells each have many properties like TEXT in common, so a new name for each of these seems extremely wasteful and unnecessary.

(We could also have used something similar like the existing TEXTBYPOS method to achieve this, but then we’d have 30’ish new “BYPOS” methods instead, and methods aren’t properties anyway).

So, to keep the property namespace under control we decided to use this commonality and implement a set of  “sub-objects” instead, one for each area.  Unsurprisingly these are named:

  • COLUMNS
  • ROWS
  • CELLS  

Each of these sub-objects are indexed and can be used to access a specific column, row or cell in the EditTable.  They all share many common properties and methods, but also expose a few type-specific ones as well.   As an example, this is how to set the CUEBANNER property for each sub-object:

ctrlEntID  = @window : ".EDT_TEST"
cueBanner  = "Test"

// Set the CUEBANNER for the second column
call set_Property( ctrlEntID : ".COLUMNS", "CUEBANNER", cueBanner, 2 )
// Set the CUEBANNER for the third row
call set_Property( ctrlEntID : ".ROWS", "CUEBANNER", cueBanner, 3 )

// Set the CUEBANNER for the cell at column 5, row 7
call set_Property( ctrlEntID : ".CELLS", "CUEBANNER", cueBanner, 5 : @fm : 7 )

// And here's the same using Object Notation Syntax
@ctrlEntID.columns{2}->cueBannner = cueBanner
@ctrlEntID.rows{3}->cueBannner    = cueBanner
@ctrlEntID.cells{5,7}->cueBannner = cueBanner

We’ll take a look at each of these sub-objects in turn over the next few posts to examine their functionality in more detail.

 

EditTables – The new “CELL” events

The OpenInsight EditTable has always supported a set of cell-related common events that are fired when a user interacts with the control:

  • CHAR
  • CHANGED
  • CLICK
  • DBLCLK
  • OPTIONS

In order to process these events properly however, it is necessary to know which cell they relate to, and this can ostensibly be found by using the NOTIFYPOS property, which is set to the position of the cell that raised the event.

In theory this approach works well, but in practice it can exhibit problems:  Events in OpenInsight are nearly always raised in an asynchronous fashion, which means that if two of those events where executed in quick succession for different cells, then NOTIFYPOS could be set to the position of the second cell, before the Basic+ event handler could process the event for the first cell, thereby leading to incorrect results.

In order to handle this better the EditTable now supports a series of corresponding “CELL” events:

  • CELLCHAR
  • CELLCHANGED
  • CELLCLICK
  • CELLDBLCLK
  • CELLOPTIONS

The only difference here is that these events pass the indexes of the cell that raised them as arguments to the event handler, thereby preserving their origin accurately.

E.g. The signature for the old CHANGED event looks like this:

Function Changed( CtrlEntID, CtrlClassID, NewData )

Whilst the signature for the CELLCHANGED event looks like this:

Function CellChanged( CtrlEntID, CtrlClassID, ColNum, RowNum, NewData )

Note that when a “CELL” event is defined the EditTable will non longer raise the ordinary event to prevent the notification from being processed twice.

(One useful example of the benefits of having the “CELL” events is that you can now use the new CELLCHANGED event for cell validation, rather than the usual POSCHANGED event, due to the fact that you know precisely where the change originated from. You also know that there actually was a change, rather than having to compare the cell’s current contents to it’s GOTFOCUSVALUE to discover this).

 

 

 

EditTables – Deleting and Inserting Rows

Support for deleting and inserting rows in the EditTable control has always been somewhat basic, exposing only minimum functionality that allows you to control how a user inserts or deletes a row in the grid.  We’ve enhanced this for version 10 by providing some fine-grain control over the row insertion and deletion process that we’ll describe below.

Imposing limits

Firstly, a couple of new properties have been implemented that allow you to set limits on the number of rows a user can add or remove from the EditTable via the keyboard: These are the MAXROWLIMIT and MINROWLIMIT properties.

MAXROWLIMIT property

When MAXROWLIMIT is set the user cannot use the Insert key to insert more rows than the number specified by this property.  The default value is “0”, which means there is no maximum limit.   Note that this property does not apply to programmatic INSERT method operations or data set by the LIST or ARRAY properties.

MINROWLIMIT property

When MINROWLIMIT is set the user cannot use the Delete key to delete EditTable rows once the minimum limit has been reached. The default value is “0”, which means there is no minimum row limit.   Note that this property does not apply to programmatic DELETE method operations or data set by the LIST or ARRAY properties.

Blocking the “Insert” and “Delete” keys

Previous versions of the EditTable allowed you to set a “Protected” property at design time that stopped all row insert and delete operations by the user.  Unfortunately, this was not actually exposed run-time (unless you adjusted a bit-flag the control’s STYLE property), so in version 10 we’ve expanded the old “Protected” property into two new properties called ALLOWROWDELETE and ALLOWROWINSERT.  These can used at both run-time and design-time.

ALLOWROWDELETE property

When set to False the user cannot use the Delete key to delete rows within an edit table.  The default value of this property is True.

ALLOWROWINSERT property

When set to False the user cannot use the Insert key to insert new rows within an edit table.  The default value of this property is True.

Managing the “Insert” and “Delete” keys

Finally, we made some changes to the way the actual inserts and deletes take place to give you an opportunity to intercept them for even more control.  In previous versions of OpenInsight the EditTable notified you of an insert or delete operation after it had taken place, via the INSERTROW and DELETEROW events respectively.  This means that if you wanted to ‘prevent’ the modification based on some run-time criteria you had to effectively undo it, which usually included some sort of unpleasant visual effect as the insert or delete was rolled back (it also resulted in a loss of formatting information or other cell-specific data that you would have to reapply).

In version 10 we’ve added a new Boolean property called ROWEVENTMODE. When set to False (the default) row insertion and deletion via the keyboard behaves in exactly the same way as previous versions of OpenInsight.  When set to True however, the INSERTROW or DELETEROW event happens before the actual operation takes place, and at this point you can do the following:

  1. If you’re using an EventScript you can return FALSE$ and the operation will be cancelled.
  2. If you’re using a code called from a QuickEvent you can set the EventStatus flag in your code to prevent the operation from proceeding further, just as you would currently do in a WINDOW CLOSE event to cancel it.

 

E.g. Stopping a row being deleted in a DELETEROW EventScript handler.

// Assumes "RowEventMode" is "True" 
//
// Check to see if there is anything in column 2 of the deleted data,
// and if so stop the delete via the event return value. 

$insert logical
if bLen( rowData<2> ) then
   // Stop the delete
   retVal = FALSE$
end else
   retVal = TRUE$
end

return retVal

 

E.g. Stopping a row being deleted in a DELETEROW QuickEvent handler

// Assumes "RowEventMode" is "True" 
//
// Check to see if there is anything in column 2 of the deleted data,
// and if so stop the delete via the Event Status 

$insert logical 
if bLen( rowData<2> ) then
   // Stop the delete
   call set_EventStatus( TRUE$ )
end

return

Of course, once you’ve allowed the Insert or Delete operation to take place you may also want to do some post-processing, and for this we’ve provided two new events: INSERTEDROW and DELETEDROW.  These have the same signature as their INSERTROW and DELETEROW counterparts and are executed after the row modification has taken place (Note that these are only fired if the ROWEVENTMODE is True).

It is also worth noting that, as with previous versions of OpenInsight, using the DELETE and INSERT methods to programatically modify the EditTable contents will not trigger the INSERTROW or DELETEROW events (or any subsequent INSERTEDROW and DELETEDROW events either).

The COMMUTERMODULE Property

As most of you will probably know, “commuter module” is the term given to a stored procedure whose main purpose is to handle event processing for a specific form.  Rather than have each individual event processed in a separate event script, quick-events are used instead to call the commuter module directly, passing it various parameters such as the name of the object firing the event, the name of the event itself, and any relevant arguments.  The commuter module then branches off to different internal subroutines to handle the event.

Following this methodology offers several important advantages:

  • Simplified code management
  • Simplified deployment
  • Improved code sharing via internal subroutines
  • Lower memory overhead (single procedure vs. multiple event scripts)

While using a commuter module like this is the recommended way of developing applications in OpenInsight, there has never been any sort of formal link between the commuter module and the form itself, which means that it is usually necessary to adopt a naming convention for this approach to work.

For example, it is common to have a commuter module with the same name as the form, or with the same name as the form and suffixed with the string “_EVENTS”.  By doing this it was easy to define quick-events to call the commuter module in the old v9 Form Designer like so:

v9 Commuter Module Quick Event

v9 Commuter Module Quick Event

The OBJ_CALL_EVENT program looks for a stored procedure with the same name as the form, or one with the same name as the form and suffixed with “_EVENTS”.  It was also possible to avoid the overhead of a lookup and call the commuter module directly by using the “@WINDOW” placeholder like this:

v9 Commuter Module Quick Event (using @WINDOW)

v9 Commuter Module Quick Event (using @WINDOW)

Or the “@WINDOW_EVENTS” placeholder like this:

v9 Commuter Module Quick Event (using @WINDOW_EVENTS)

Of course, even with this approach the form still wasn’t actually linked to it’s commuter module, rather it was only linked to “OBJ_CALL_EVENTS” or a fictitious entity called “@WINDOW”.

In version 10 we’ve added a new WINDOW property called COMMUTERMODULE, which simply contains the name of the stored procedure to use (this can be any valid name – you are no longer limited to one based on the name of the form, though we do suggest you keep this convention to help organize your application):

CommuterModule Property

CommuterModule Property

When the form is saved and compiled this stored procedure is linked to the form with a “used-by” relationship, thereby making deployment easier as you will see the link when you create your RDK definition records.

Another benefit of this is that you can quickly open your commuter module from the form by using the “View Commuter Module” button on the Form Designer toolbar:

View Commuter Module button

View Commuter Module button

Finally you can easily set your quick events to call your commuter module in the Event Designer like so:

Commuter Module QuickEvent

Commuter Module QuickEvent

Note that it uses an “@COMMUTER” placeholder – this is replaced with the contents of the COMMUTERMODULE property at runtime.

(You can still use the previous @WINDOW/_EVENTS or Obj_Call_Events methods if you wish – those options still exist.)

So, this is the first step in tightening the relationship between a form and it’s commuter module.  There is certainly scope for more integration between the two and this is something that we hope to pursue during subsequent releases.

(Disclaimer: This article is based on preliminary information and may be subject to change in the final release version of OpenInsight 10)

Context Menus in OpenInsight 10 – Part I

Using context menus in previous versions of OpenInsight has always been something of a chore: they were not well documented and they were subject to several limitations:

  • They could only be attached to a control programmatically, rather than via the Form Designer.
  • The context menu designer tool would name a menu based on the control it was supposed to be attached to – there was no real concept of sharing a menu between controls.
  • They were limited to a single level – no sub-menu nesting was allowed.
  • They were difficult to modify at runtime.

These issues made them quite onerous to use, which is unfortunate as context menus are an important part of modern UI design, having been in widespread use across the OS since Windows 95.

With version 10 we went back to the drawing board and completely redesigned them to make them first class UI citizens and solve the problems outlined above.

The Context Menu Designer

One of the new tools in the IDE is the Context Menu Designer, which allows you to define the structure of the menu along with any quick events (Event scripts are not supported for context menus).

Context Menu Designer (WIP)

Context Menu Designer (WIP)

Menus saved by the designer are given simple names in the same format as any other repository entity – they are no longer based on the name of a specific control.  They can then be attached in the Form Designer by using an object’s CONTEXTMENU property.

(Note that like normal WINDOW menus they also support nested structures as they share the same code-base.)

The CONTEXTMENU property

Forms and controls now support an explicit CONTEXTMENU property which is the repository ID of a saved context menu.

ContextMenu Property

ContextMenu Property

At runtime, when a user right-clicks on a control, the Presentation Server looks at the CONTEXTMENU property to find the name of an attached menu, and, if found, displays it.

When the user selects an item from context menu a MENU event is raised and sent to the quick event target defined in the designer.

This is a much simpler and streamlined process.

Of course, that’s not the end of the story as there are times when the context menu will need to be adjusted before it is displayed at runtime, depending on factors like the state of it’s parent control and so on.  We’ll take a look at how to do that in the next post.

(Disclaimer: This article is based on preliminary information and may be subject to change in the final release version of OpenInsight 10).