Tag Archives: Events

The SCALED event

As covered in our recent posts on scaling and High-DPI, OpenInsight now has the capability to dynamically alter the scale of a form at runtime, taking care of layout, fonts and images.  However, there may be circumstances where this is not sufficient – perhaps you need to tweak the layout yourself, or perhaps you need to display a specific image rather than rely on a DPI Image List.  In this case you will need to know when the scaling operation has taken place, and you can handle this in the new SCALED event:

SCALED event

This WINDOW event is triggered when the SCALEFACTOR property is changed or when the form is moved to another monitor with a different DPI.

bForward = SCALED( ctrlEntID, ctrlClassID, origDpiX, origDpiY, origScaleFactor, |
                                           newDpiX, newDpiY, newScaleFactor )

The event is passed the following event-specific arguments:

  1. The original X DPI value
  2. The original Y DPI value
  3. The original SCALEFACTOR value
  4. The new X DPI value
  5. The new Y DPI value
  6. The new SCALEFACTOR value

The system performs no default processing for this event.


Handling layout for scaled forms

Of course, this leads us to one of the main issues with handling scaling: how do you get and set layout properties like SIZE for a scaled form? What units are used?

There are basically two choices available:

  1. Use Device Independent Pixels (DIPs): With this method all coordinates are treated as though the form is scaled at 96 DPI with a scale factor of 1.  The system is then responsible for mapping them to actual pixels at runtime.
  2. Use Pixels (PX): With this method the coordinates passed are treated as actual screen pixels regardless of the DPI or scale factor.

Using DIPs may seem easiest at first, especially in terms of backwards compatibility with existing code, but it does have some drawbacks:

  • Positioning can be imprecise due to integer rounding, and you may sometimes find a case where you need complete accuracy.
  • Some properties and events cannot use DIPs at all (mainly those that relate to screen coordinates), thereby leading to the need for some type of dual coordinate system, resulting in added complexity and possible confusion.

So, to keep things simple, OpenInsight operates in Pixel mode by default, which means it keeps a single and accurate coordinate system.  Remember, scaling is an “opt-in” system, meaning that none of your existing forms will scale unless you specify otherwise (via the DPISCALING and SCALEFACTOR properties), so you can review your code before enabling it and ensure that you don’t encounter any problems.

However, even though the default coordinate system is Pixels we don’t want to remove the choice of using DIPs if you prefer, so forms now support a new SCALEUNITS property that allows properties like SIZE to operate in either DIP or Pixel mode.


This is a WINDOW property that defines the units used when accessing layout properties like SIZE, CLIENTSIZE, TRACKINGSIZE and so on.  Note that it also affects events like BUTTONDOWN and methods like TEXTRECT too.

It accepts the following values:

  • “0” – Scaling units are Pixels
  • “1” – Scaling units are DIPs

Example: Scale a form and examine it’s SIZE using different SCALEUNITS

* // SCALEUNITS property equates - (from PS_WINDOW_EQUATES)
 equ PS_SCU_PIXELS$ to 0
 equ PS_SCU_DIPS$   to 1

* // Assume we are currently running with Pixel units
call set_Property_Only( @window, "SIZE", 10 : @fm: 10 : @fm : 400 : @fm : 300 )

* // Now scale the window to twice its normal size ( actual XY remains constant
* // for a form when setting SCALEFACTOR - only the width and height change)
call set_Property_Only( @window, "SCALEFACTOR", 2 )

* // SIZE returns 10x10x800x600 
pxSize = get_Property( @window, "SIZE" )

* // Now set the scaling units to DIPS
call set_Property_Only( @window, "SCALEUNITS", PS_SCU_DIPS$ )

* // SIZE returns 5x5x400x300 
dipSize = get_Property( @window, "SIZE" )

* // Note that the X and Y returned in the DIPs SIZE above have also been scaled. 
* // The form hasn't moved, but the units of measurement have changed, so the 
* // location is reported relative to a _theoretical_ scaled desktop size.

At first glance it may seem that the SCALEUNITS property should be a SYSTEM property rather than a WINDOW one, but bear in mind that OpenInsight applications may inherit from one another, and executing a form designed for one set of units while running in another application with a different “global” setting would undoubtedly cause problems.  Of course there’s nothing to stop you setting the SCALEUNITS to DIPs in a promoted CREATE event for your own applications but that’s another story…


Scaling helper methods

There are six new WINDOW methods you can use to help with manual scaling – they convert between Pixels and DIPs based on the form’s current DPI and SCALEFACTOR (They are not affected by the SCALEUNITS property):


The “SCALE” methods perform a DIPs to Pixel conversion.


The “UNSCALE” methods perform a Pixel to DIPs conversion.

(You only really need the SCALEVALUE and UNSCALEVALUE methods, but the other four have been added to make things a little more convenient for you).


This method takes an unscaled FONT property and scales it relative to the current scale factor of the form.

scaledFont = exec_Method( @window, "SCALEFONT", origFont )


This method takes an unscaled SIZE property and scales it relative to the current scale factor of the form.

scaledSize = exec_Method( @window, "SCALESIZE", origSize )


This method takes an unscaled value and scales it relative to the current scale factor of the form.

scaledVal = exec_Method( @window, "SCALEVALUE", origVal )


This method takes a scaled FONT property and unscales it relative to the current scale factor of the form.

unscaledFont = exec_Method( @window, "UNSCALEFONT", scaledFont )


This method takes a scaled SIZE property and unscales it relative to the current scale factor of the form.

unscaledSize = exec_Method( @window, "UNSCALESIZE", scaledSize )


This method takes a scaled value and unscales it relative to the current scale factor of the form.

unscaledVal = exec_Method( @window, "UNSCALEVALUE", scaledVal )

Example: Moving a control using DIP coordinates on a form with Pixel SCALEUNITS

* // Example - Move a control using DIP coordinates. We get the current pixel
* //           size, unscale it so we have the value as it _would_ be at
* //           96DPI/ScaleFactor 1 (i.e. DIPs), offset it by 10 DIPs, scale
* //           it back to Pixels and and then move it.
* // Get the current scaled size (pixels) - assume we have a SCALEFACTOR of 1.5
ctrlSize = get_Property( myCtrl, "SIZE" )

* // Unscale it back to 96DPI/ScaleFactor 1.0 - i.e. to DIPs
ctrlSize = exec_Method( @window, "UNSCALESIZE", ctrlSize )

* // Adjust it to whatever we need (assume we want to offset it by 10 DIPs
* // (10 pixels at 96 DPI)
ctrlSize<1> = ctrlSize<1> + 10
ctrlSize<2> = ctrlSize<2> + 10
* // And ask the parent form to calculate where it _should_ be using the 
* // current scale factor
ctrlSize = exec_Method( @window, "SCALESIZE", ctrlSize )
* // And move it using pixels ...
call set_Property_Only( myCtrl, "SIZE", ctrlSize )

The previous example is rather contrived and is really only there to highlight how the methods can be used.  Another way of doing this would be to switch to DIPs using the SCALEUNITS property like so:

* // SCALEUNITS property equates - (from PS_WINDOW_EQUATES)
equ PS_SCU_PIXELS$ to 0
equ PS_SCU_DIPS$   to 1

* // Set the scaling units to DIPS 
scaleUnits = set_Property( @window, "SCALEUNITS", PS_SCU_DIPS$ ) 

ctrlSize = get_Property( myCtrl, "SIZE" )

* // Offset the control by 10 DIPs
ctrlSize<1> = ctrlSize<1> + 10 
ctrlSize<2> = ctrlSize<2> + 10

call set_Property_Only( myCtrl, "SIZE", ctrlSize )

* // And restore the SCALEUNITS
call set_Property_Only( @window, "SCALEUNITS", scaleUnits )

The AUTOSCALE property

By default OpenInsight maintains automatic scaling for all controls on a form, even after you’ve manually set a scaled property yourself.  However, you can opt out of this behaviour by using the boolean AUTOSCALE property:

  • When set to TRUE (the default value) it enables scaling for a control.
  • When set to FALSE no automatic scaling is performed.

This property applies to all controls (but not to WINDOW objects for obvious reasons).

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

QuickEvents, Commuter Modules and Passing-By-Reference

As you may (or may not) know variables in Basic+ are passed to stored procedures “by reference”, meaning that if you change a passed variable in the called procedure, that change is reflected in the calling routine (a fuller explanation of how this works can be found here). This behavior is critical to the way many system functions work (such as iconv and oconv) and is very useful in returning more than one item of data from a called procedure.

However, one place where this rule breaks down is when calling stored procedures via a QuickEvent, such as routing an event to a commuter module like so:

Commuter Module QuickEvent

Example: Calling a Commuter Module from a QuickEvent

When you call a stored procedure in this way the system eventually passes your request to a routine called ExecNpHandler() which dispatches the event and its arguments to the desired target,  However at this point the pass-by-reference chain gets broken because a copy of the argument is passed to the stored procedure rather than the original.

For example, if we used Send_Event() to trigger the OMNIEVENT event in the above example, and the commuter module changed Param2, the Send_Event() caller would not see the change (Note that if you use an Event Script handler then passing the event arguments by reference works as you would expect, and you will see changes made to your arguments by the Event Script handler).

While working on the v10 IDE this proved to be something of a problem because the framework relies on a series of OMNIEVENT calls to pass messages between various entities, and sometimes arguments are updated to let the caller know of things like state changes and suchlike.  With something as complex as the IDE, writing the events as a series of Event Scripts was impractical so we took the opportunity to update ExecNpHandler() to respect the pass-by-reference paradigm instead – Now you get to see your changes in a consistent manner regardless of whether you prefer Event Scripts or QuickEvents.

So, is this change likely to impact you? In most cases the answer is no as ExecNpHandler() is normally the last handler to be called in the event chain, and any changes to passed arguments are usually ignored.  Where this might be an issue is when:

  1. You call forward_Event() from an Event Script, or fire an event via Send_Event(), and
  2. You rely on the arguments you passed to either of the above functions remaining unchanged, and
  3. You changed the arguments passed to you in the commuter module, either by carelessness or design.

In this set of circumstances you will probably see an effect, and you may have to modify your code accordingly.

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

Promoted Events and the Repository

One of the most powerful programming features of OpenInsight is the “Promoted Event” model, allowing you to write “global” event handing code that can be triggered for a variety of situations, such as for all objects of a certain type, or for all objects in an application, and so on.  This helps to centralize your code-base and restrict unnecessary duplication, thereby making development faster and more robust.

However, promoted events have also been one of the most opaque parts of the system and  their use is somewhat awkward and error-prone because they rely on the dark art of naming conventions and manual record copying between tables.  In an effort to rectify this we’ve integrated them into the OpenInsight Repository so they can be tracked properly and you can see at a glance exactly what is in your system.  

Promoted events fall into one of 5 generic categories:

 Category                         Example SYSREPOSEVENTS key
 ========                         ==========================
 3) TYPE specific              -> SYSPROG*..OIWIN*
 5) EVENT specific             -> SYSPROG*ACTIVATED*

So to enable their integration we’ve added three new entity types:

  • PROMOTEDEVENT (source code)
  • PROMOTEDEVENTDBG (debugger symbol table)
  • PROMOTEDEVENTEXE (object code)

Each of these types has a Repository key structure that derives from the actual promoted event key itself like so:

 SYSREPOSEVENTS key                 Repository key 
 ==================                 ==============

Some of you may look twice at the use of the “_” character for the CLASSID and ENTID Repository key parts:  This is actually used as a placeholder to denote a null part in the promoted event key itself – their use is necessary because the Repository reacts poorly to a null CLASSID or ENTID.

We’ve also added a new stored procedure called SYNCH_REPOS_PROMOTED_EVENTS which can scan your SYSREPOSEVENTS and SYSREPOSEVENTEXES tables to create any missing  entities so it’s easy to bring your existing promoted events into the Repository,

Of course integration with the Repository isn’t the end of the story – now that promoted events are recognized as first-class citizens we need to provide the tools in the IDE to create and maintain them… but that’s a story for another time…

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


We’ve already taken a look at the new FILESYSTEM object in a previous post, but this time we’re going to focus on a new method we’ve added called WATCHDIR.

This method allows you to monitor the contents of one or more directories on the system and be notified of any changes occurring within them.  It’s API is quite simple and takes up-to three arguments:

  1. The name of the directory to watch (required).
  2. A optional boolean flag denoting if you wish to include sub-directories. (defaults to FALSE$).
  3. An optional set of bit-flags detailing the kind of changes you are interested in.  By default WATCHDIR notifies you of file creation, changes to the name, and changes to the “Last-Write” time.


$insert msWin_FileNotify_Equates

// Only watch for files being created in the specified dir ...
bIncludeSubDirs = FALSE$
call exec_Method( "FILESYSTEM", "WATCHDIR", "c:\temp\incoming", |
                  bIncludeSubDirs, watchFlags )

When a change occurs the FILESYSTEM object raises a CHANGED event to notify you of the fact,  As with any other OI window or control you can write your own FILESYSTEM CHANGED event handler to respond to this – note that this event is per application, not per window.

Like the standard CHANGED event the relevant change information is passed in the “NewData” argument – in this case “NewData” contains a dynamic array with two fields:

<1> The name and path of the file being changed
<2> A code specifying the type of change


$insert msWin_FileNotify_Equates

changeFile = newData<1>
changeCode = newData<2>

info = ""

begin case
   case ( changeCode = FILE_ACTION_ADDED$ )
      info = "Added"
   case ( changeCode = FILE_ACTION_REMOVED$ )
      info = "Deleted"
   case ( changeCode = FILE_ACTION_MODIFIED$ )
      info = "Modified"
   case ( changeCode = FILE_ACTION_RENAMED_OLD_NAME$ )
      info = "Renamed From"
   case ( changeCode = FILE_ACTION_RENAMED_NEW_NAME$ )
      info = "Renamed To"
end case

call send_Info( info : " " : changeFile )

Technical note: The WATCHDIR method is based on the underlying ReadDirectoryChangesW Windows API function, details of which can be found here.

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

Button controls

Perhaps one of the controls most in need of a face-lift in OpenInsight is the Button (a.k.a PUSHBUTTON) control, and in this post we’ll take a look at some of the new features we’ve added to it for version 10.

Image API

Buttons in OpenInsight have always supported background images and version 10 is no different.  However we’ve extended the number of image states from 6 to 10 to give you a few more options if you want to use them:

  1. Up
  2. Down
  3. Disabled
  4. <not used>
  5. Up with focus
  6. Down with Focus
  7. Hot
  8. Hot with focus
  9. Default
  10. Default with focus

Of course you don’t have to supply all of these images – the system will attempt to pick the closest match based on the IMAGECOUNT supplied.  Access to the image properties is exposed via the normal Image API with the exception of the IMAGENUMBER property which is managed automatically depending on the button state.

Glyph API

One of the biggest drawbacks with using buttons in previous versions of OpenInsight is that images have only ever been applied to the background as a whole.  In order to create a button with an icon (or glyph, as we’ll refer to it henceforth) it has always been necessary to provide an image file with the entire button background drawn on it as well as the required glyph and text.  This makes it very difficult to provide a solution that looks good across different color schemes and visual styles, and it also makes any sort of runtime customization problematic too.

For version 10 a new API has been added for buttons called the “Glyph API”. This allows you to specify an image for the button that is drawn on top of the normal background like so:

Classic-style button with glyph

Classic-style button with glyph

XP-style button with glyph

XP-style button with glyph

Aero-style button with glyph

Aero-style button with glyph

Win8-style button with glyph

Windows 8-style button with glyph

It is exposed via the following properties:

  • GLYPH (similar to the BITMAP or IMAGE property)

These properties are very similar to their counterparts in the normal Image API with the exception of the following Button-glyph specific ones:


This property specifies how the glyph is laid out in relation to the text, and can be one of the following values:

  • “0” – Glyph to the left, text to the right
  • “1” – Glyph to the top, text to the bottom
  • “2” – Glyph to the right, text to the left
  • “3” – Glyph to the bottom, text to the top.
Buttons showing  glyph layouts

Aero-style buttons showing glyph layouts


This property is simply the number of pixels between the glyph and the text.

Where’s the GLYPHNUMBER property?

Just as the Button Image API has no IMAGENUMBER property there is no corresponding GLYPHNUMBER property either – this is because you can provide more than one image for a glyph and the system will automatically select one for you based on the button state (just like with background images).  These states are:

  1. Button up
  2. Button down
  3. Button disabled
  4. Button hot
  5. Button default

Note that if you don’t supply a disabled Glyph image and you disable the button the system will draw a grayed version of the glyph for you:

Button with disabled glyph

Aero-style buttons with system-drawn disabled glyph

Flat buttons

Flat “toolbar” style buttons are supported by the boolean FLAT property.  I.e. the actual background is not painted until the mouse is moved over the button.

Flat button

Aero-style flat button

Flat button with translucency

Aero-style flat buttons with 50% translucency

Custom colors

The button BACKCOLOR property fully supports custom colors and generates a set of matching 3D highlight and shadow colors to use when rendering.

Button with red BACKCOLOR

XP-style button with red BACKCOLOR

The FORECOLOR property also makes a welcome return and is now respected regardless of the visual style in use.

Button with red FORECOLOR

Aero-style button with red FORECOLOR

Extended mouse support

Like the updated Label control the Button now supports the following new properties when the button is in the “hot” state (i.e. the mouse is moving over it):


It also supports the new MOUSEOVER event so you can easily track mouse movements without having to resort to using WINMSG events.

Text Alignment and position

TEXTORIGIN property is provided that allows you to specify the exact XY position that you wish the text to be drawn at in a similar manner to the GLYPHORIGIN property.  Horizontal text alignment is also supported by the TEXTALIGN property.

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

Hyperlink controls

Following on from the previous post on Label controls another new item we’ve added to OpenInsight is the Hyperlink control, which is essentially a specialized Label control that allows you to implement clickable links on your forms.

Hyperlink Control

Hyperlink Control

Barring HTML rendering it supports all the other properties of a Label control as well as adding a few others:

  • LINK


If this property is TRUE then the control ensures the text is underlined when the mouse hovers over it.

LINK property

This property contains the command string to execute when the link is (single) clicked. it can be any valid Windows command string (internally it is passed to the Windows ShellExecute function).

Note that that the CLICK and DBLCLK events are still fired as normal even if the LINK property is blank, so you still have full control over the hyperlink target.


This specifies the cursor to use when the mouse is over the link text.  It defaults to the standard “hand” cursor but can be set in the same way as the normal OpenInsight CURSOR property.


When the command string in the LINK property is executed the result of the operation (as returned from the ShellExecute function) is placed in the LINKRESULT property for further examination if you wish (ShellExecute normally returns a value < 32 if there is a problem executing a command).


If this property is TRUE the link will be displayed using the VISITEDFORECOLOR property when it has been clicked at least once.


This property specifies the color to use for visited links (i.e. those that have been clicked and have a SHOWVISITED property of TRUE).

The GO method

The Hyperlink control also supports a new GO method that executes the contents of the LINK property as though it had been clicked.  The return value from this method is the same as the value returned in the LINKRESULT property.

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

Label controls

Over the past few posts we’ve taken a look at some of the new controls we’ve added to OpenInsight in version 10, but during the development process we’ve also taken the opportunity to upgrade some of the existing controls as well.  In this post we’ll take a look at the humble Label (or STATIC) control and examine some of the new features that have been implemented for it.

Background Images

The Label control now exposes the full Image API in the same way as the version 10 OpenInsight WINDOW object does.

Label control with background image

Label control with background image

Gradient background colors

The BACKCOLOR property now supports gradients in the same way that the current OpenInsight WINDOW object does, along with the associated GRADIENTSTYLE property.

Label control with gradient background

Label control with gradient background

Translucent background

The Label control may use a translucent background via the TRANSLUCENCY property.

Label control with translucent background

Label control with translucent background

Aero Glass support

As part of OpenInsight’s Aero Glass support, transparent labels drawn on glass in Vista and Windows 7 have the recommended “glow effect” enabled to improve readability:

Label controls on Aero Glass

Transparent Label controls on Aero Glass

Text Alignment

Vertical as well as horizontal text alignment is now supported via the TEXTALIGN property:

  • “0” Top-Left
  • “1″ Top-Center
  • “2″ Top-Right
  • “3″ Middle-Left
  • “4″ Centered
  • “5″ Middle-Right
  • “6″ Bottom-Left
  • “7″ Bottom-Center
  • “8″ Bottom-Right
Label control with bottom-center text alignment

Label control with bottom-center text alignment

A TEXTORIGIN property is also exposed that allows you to specify the exact XY position that you wish the text to be drawn at in a similar manner to the standard IMAGEORIGIN property.

Mouse-over support

Label controls can now respond to a mouse-over or “hot” state via the new HOTFORECOLOR, HOTFONT and HOTBACKCOLOR properties.  When set these properties are used in place of their standard counterparts (FORECOLOR, FONT and BACKCOLOR) when the mouse is over the control.

Mouse event support

The following standard events are now exposed for Label controls:


In addition to this we’ve also provided a new MOUSEOVER event along with a notification flag for when the mouse enters and exits a control (We intend to extend the MOUSEOVER event to cover all OpenInsight controls).

Edge styling

By default normal Windows Label controls actually support a “edge-style” that allows them to have a sunken or etched border, or even display themselves as a single vertical or horizontal etched line.  Although this capability can be used in earlier versions of OpenInsight via raw style-bit manipulation we’ve exposed it fully in Version 10 via the EDGESTYLE property.  This can be one of the following values:

  • “0” – No border
  • “1” – Sunken border
  • “2” – Etched Horizontal line along the top edge
  • “3” – Etched Vertical line along the left edge
  • “4” – Etched Frame
Label control with a sunken border

Label control with a sunken border

Label control with an etched frame

Label control with an etched frame

Text handling

We’ve exposed a couple of new text handling properties: AUTOELLIPSES and WORDWRAP.  The former allows truncated text to be suffixed with the ellipses string  “…”, while the latter allows text to wrap in an effort to avoid truncation where possible.

Label control with AUTOELLIPSES enabled

Label control with AUTOELLIPSES enabled

HTML Text rendering

The Label control now supports simple inline HTML rendering via the boolean DRAWHTML property.  The following tags are currently supported:

  • <b>Bold</b>
  • <i>Italic</i>
  • <u>Underline</u>
  • <strike>Strikeout</strike>
  • <sub>Subscript</sub>
  • <sup>SuperScript</sup>
  • <font>Font</font>
  • <br>

The font tag supports the following attributes:

  • color
  • bgcolor
  • face
  • size
Label control with HTML text rendering

Label control with HTML text rendering

 (As with the aforementioned MOUSEOVER support we’re intending to extend HTML text rendering to other controls where appropriate)

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