25 June 2013

What to do with an OLE_COLOR?

An OCX/ActiveX control color property can be assigned any valid Win32 color reference. However, the OCX/COM libraries provide a special data type for color properties, the OLE_COLOR data type. This new type was invented to give VB-like programs an opportunity to differentiate between a normal Win32 color reference and system colors. These programs could then present a special color-selection dialog box that allowed the selection of system colors. The snapshot of the GB32 Ole-color selection is shown below.

image

RGB colors are of type COLORREF
Like an RGB-color value, an OLE_COLOR data type is internally represented as a 32-bit long integer. An RGB-color is referred to as a COLORREF value and is used with GDI device context functions. A COLORREF is simply defined as a 32-bit value used to specify an red, green, and blue components of a color requiring only 3 bytes. When specifying an explicit RGB color, the COLORREF value has the following hexadecimal form.

0x00bbggrr

The low-order byte contains a value for the relative intensity of red, the second byte contains a value for green, and the third byte contains a value for blue. The high-order byte must be zero. The maximum value for a single byte is 0xFF.
To create a COLORREF color value, you can use the GB32 RGB() function. To extract the individual values for the red, green, and blue components of a color value, use the GetRValue, GetGValue, and GetBValue functions, respectively. For performance reasons these GFA-BASIC 32 functions are directly translated to assembly code; they are not implemented as function calls.

The OLE_COLOR type
When a COM object property (most often .ForeColor and .BackColor only) requires an OLE_COLOR color, you can either pass an RGB  value (COLORREF) or a COM specific formatted system color index value. A COM specific format has it’s high-byte set 0x80. An OLE_COLOR can have two formats only:

  • 0x00bbggrr (COLORREF value)
  • 0x800000xx, where xx is the index used by GetSysColor().

The object doesn’t do much with the OLE_COLOR value, it is more a kind of a storage type. For instance, you cannot pass an OLE_COLOR to a GDI device context handle. GDI doesn’t know what to do with a COM formatted system index color (0x800000xx). The OLE_COLOR value is simply saved in the private data of the COM object and remains unchanged until the application explicitly changes the value again. This way, the Get-color-property variant of the Put-color-property will return exactly the same value as was first put in.

How the OLE_COLOR is used
Since the format of the OLE_COLOR data type isn’t known to Win32 drawing functions, they must be converted to RGB colors first. Usually, the OLE_COLOR is converted on a just-in-time basis. Just before a painting operation is performed the OLE_COLOR (32-bit long integer) is tested for a high-byte value of 0x80. When the high-byte is indeed 0x80, the low-byte value is used as a parameter to the GetSysColor() API function, which in turn returns the RGB color value of the specified display element. See the code below.

Aside: Identifying display elements
Display elements are the parts of a window and the display that appear on the system display screen. These elements are identified using the API COLOR_* constants, like COLOR_BTNFACE, COLOR_WINDOW, etc. These API constants may also be used in the GFA-BASIC 32 function SysCol(idx), which is slightly easier to use and a bit faster due to caching.

Dim rgb% = SysCol(COLOR_WINDOW)

The GFA-BASIC32 OLE_COLOR Constants
GFA-BASIC 32 also defines a set of OLE_COLOR constants to identify the system display elements. These constants are very much like the Windows API COLOR_* constants. However, instead starting their names with ‘COLOR_’ they start with ‘col’, like colBtnFace and colWindow. These GB32 OLE_COLOR constants have the format of 0x800000xx, where xx is the index for the display element. See the code below.

Convert an OLE_COLOR
When you want to use an OLE_COLOR value, make sure to convert the OLE_COLOR to a COLORREF (RGB) value first. This is the only color format Win32 understands. In GB32 you get hold of an OLE_COLOR when you use one the col* constants or retrieve a color from one of the Ocx-color properties. For instance, when you want to use the same color as the form’s background, you might very well end up with an OLE_COLOR with the high-byte set to 0x80.

Now, there are two possible ways to convert an OLE_COLOR to a COLORREF value.

1. Manually, in your code. For example this converts to an RGB-value:

Trace Hex(SysCol(colBtnFace))   ' =0 (SysCol: what is a colBtnFace?)
Trace Hex(colBtnFace)           ' =8000000F (an OLE_COLOR)
Trace Hex(OleToRGB(colBtnFace)) ' =F0F0F0 (the RGB value)
Trace Hex(OleToRGB(0x667788))   ' =667788 (no conversion)

Function OleToRGB(olecolor As Long) As Long Naked
  If (olecolor And 0xFF000000) == 0x80000000
    Return SysCol(olecolor And 0xFF)  ' LoByte
  Else
    Return olecolor                   ' RGB!
  EndIf
EndFunc

2. Use the system OLE function OleTranslateColor()

Declare Function OleTranslateColor Lib "oleaut32.dll" ( _
  ByVal OleColor As Long, _
  ByVal hPal As Handle, _
  ByRef ColorRef As Long) As Long

Dim rgb As Long Long

If OleTranslateColor(colBtnFace, Null, rgb) == S_OK Then _ Trace Hex(rgb)

The second option using OleTranlateColor() might be preferable because it can also return other GDI color formats, like a palette-index value. In addition in case of an error, it let you investigate the type of the error. See the SDK for more info.

More flexibility
You can use OLE_COLOR types with the GB32 graphic commands, though. All drawing statements, font statements, and color statements accept an OLE_COLOR type. GB32 converts the OLE_COLOR to a COLORREF before it invokes the corresponding GDI function.

Another nice page on GB32

Sometimes I scan the internet for GFA-BASIC 32 references. Recently I stumbled upon this site http://basic.mindteq.com/index.php?i=81 with a comment from Bruce Bell. He wrote a very nice summary of the GFA-BASIC 32 essentials. Chapeau!

23 June 2013

The Align Property of Command, Checkbox, and Option

The Align property of the Ocx controls Command, Checkbox and Option differ from other Ocx controls. The documentation for Align says that it indicates how an Ocx control is placed inside its parent or owner Ocx control, also called docking. Several predefined constants (basNoAlign (0), basTop (1), basBottom (2), basLeft (3), and basRight (4))  are provided to help using the correct docking value with Align.

The buttons are different
In GFA-BASIC32 the Windows BUTTON class controls (push)button, checkbox, and radio-button are implemented as Ocx Command, Ocx Checkbox, and Ocx Option, respectively. The position of the contents of the BUTTON control can be changed by applying a predefined BUTTON-style alignment value. These are defined in the winuser.h SDK include file:

#define BS_LEFT             0x00000100
#define BS_RIGHT            0x00000200
#define BS_CENTER           0x00000300
#define BS_TOP              0x00000400
#define BS_BOTTOM           0x00000800
#define BS_VCENTER          0x00000C00


These values can be applied using API functions or using the WinStyle property of the Ocx controls. In addition, these style bits can be set using the Align property of the BUTTON class Ocx controls (Command, Checkbox, and Option). However, the values that you can assign to Align are different than the values used with the docking purpose of Align. The documentation lacks proper explanation of using the Align property with buttons. (At least in the English help file.)So let me fill the gap.
The position of the contents of the BUTTON controls can be set using a value between 0 and 10, but not 3 and 7. There meaning - as described by the official GB32 documentation -and the corresponding button styles are listed below.

Value Position BUTTON Style Value
0 Center Normal H/V centered 0x00000000
1 Left BS_LEFT (vertical centered) 0x00000100
2 Right BS_RIGHT (vertical centered) 0x00000200
3 no meaning* BS_CENTER 0x00000300
4 Top BS_TOP 0x00000400
5 TopLeft BS_TOP | BS_LEFT 0x00000400 | 0x00000100
6 TopRight BS_TOP | BS_RIGHT 0x00000400 | 0x00000200
7 no meaning* BS_TOP | BS_CENTER 0x00000400 | 0x00000300
8 Bottom BS_BOTTOM 0x00000800
9 BottomLeft BS_BOTTOM | BS_LEFT 0x00000800 | 0x00000100
10 BottomRight BS_BOTTOM | BS_RIGHT 0x00000800 | 0x00000200


When one of the position values from the first column is passed to the Align property the value is shifted left 8 bits and then sent to the BUTTON control using

SendMessage(ocx.hWnd, BM_SETSTYLE, position, 1)
* The no meaning values 3 and 7 can be used in code, not in the Form Editor. When used in code, the internal GB32 function that implements Align will accept any value between 0 and 15! It simply shifts the value 8 bits left and sends it to the BUTTON control.

So, the value of the Align property is used to position the contents of a BUTTON control Ocx. The value is converted to a BS_* constant value as defined in the SDK and passed to the BUTTON control. In this particular case the Align property has a different meaning. Perhaps, it should be named ‘Alignment’ as with the Label Ocx controls.