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:
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:
The system performs no default processing for this event.
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:
Using DIPs may seem easiest at first, especially in terms of backwards compatibility with existing code, but it does have some drawbacks:
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 andSCALEFACTOR 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 likeSIZE, CLIENTSIZE, TRACKINGSIZE and so on. Note that it also affects events likeBUTTONDOWN and methods like TEXTRECT too.
It accepts the following values:
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…
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 notaffected 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 SCALEUNITSproperty 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 )
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:
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).