28 November 2010

Download new update

General note on updates. Go to the Download Page (button on the top of the blog).

Update of Build 1169 (2)

This is the second update of Build 1169. The IDE (GfaWin32.exe) isn't changed and still has build number 1169; however the runtime in the previous build-release 1169 (1) contained a new bug.

The CommDlg property .FileName didn't return the selected folder when CommDlg.ShowFolders was used. This is now fixed and the .FileName property should now return the correct filename(s) or folder. Note that the .FileName property was associated with three bugs. I hope they are all fixed now.
The runtime has build number 1169 now as well.


22 November 2010

ImageList Ocx Part 2

In the introduction to the GFA-BASIC 32 ImageList Ocx (1) the emphasis was placed on the creation of the image list common control, which – as we saw - is delayed to the moment the first picture is added to the control. All images have the same size. The size is determined by the first picture's height and width, or the size values set using the .ImageWidth and .ImageHeight properties of the ImageList Ocx.  The .ColorFormat property specifies how the pictures are added and whether or not a mask is generated. The color for the mask is  specified using the .MaskColor property.

After the creation
Once the underlying image list common control is created, the .ColorFormat, .ImageWidth and .ImageHeight properties fail to accept a new value. These properties raise the E_FAIL COM error. This is also demonstrated when you use the 'ImageList Data' dialog box to add images to an ImageList Ocx. The upper left controls contain the options to create the image list common control. You may specify the required size and color format. The default settings are zero for both the size properties, and the 0 (device dependent/mask included) ColorFormat property.
After adding an image these control are disabled, because ImageList_Create() has been invoked using the settings from these controls.  
Using masks in GFA-BASIC 32 is a bit confusing because its setting is the opposite of Windows API.

Masks in GFA-BASIC 32
By default GFA-BASIC 32 creates a mask for each and every picture you add to the ImageList control. Whether or not the mask is added to the underlying image list common control is determined by the .ColorFormat property value.
In contrast with the API specifications, GFA-BASIC 32 uses a reversed setting for the mask option. The flags argument in the ImageList_Create() function specifies the mask using the ILC_MASK bit value. In GFA-BASIC 32 you don't explicitly specify  a mask by setting bit 1 to 1; in GFA-BASIC the .ColorFormat value must hold a zero value in bit 1.

.ColorFormat = 0    '(default) create mask
.ColorFormat |= 1   ' no mask

Just before creating the image list common control GFA-BASIC inverts the first bit and includes it in the flags parameter passed to the ImageList_Create() function.
However, when you explicitly exclude a mask (by setting .ColorFormat |= 1) GFA-BASIC 32 will continue to create masks. However, when picture and the mask are added they are simply ignored by the image list common control.
Note Excluding a mask will result in loss of data when you add an icon to the image list. Therefore GFA-BASIC 32 uses a mask at all times.

Purpose of UseMaskColor and MaskColor Properties
When you add an icon into the list, GFA-BASIC uses its internal mask. If a bitmap or a metafile is added, a mask is created in memory. When .UseMaskColor == 0 the mask is simply a black monochrome bitmap of the same size, all pixel bits are set to zero. However, when you set .UseMaskColor to a nonzero value, the pixels in the image that have the same color value as the .MaskColor setting have a corresponding white color in the monochrome mask bitmap. This opens up the possibility to draw the image transparently. How the image is drawn later depends on more factors than the availability of a mask bitmap only, however.
You can change both UseMaskColor and the MaskColor properties before adding the next image to the list. That way you can have GFA-BASIC generate the correct mask for the image to add. (Each image might have a different transparency color.) 
UseMaskColor and MaskColor are a per image setting when adding a Picture to the list.

The BackColor Property
The only property we didn't discuss so far. The .BackColor property isn't used in the creation of the image list common control and it isn't used in the addition of images to the list. The .BackColor property setting is used when we want to get something out of the image list control. It is used in drawing operations and when a Picture object is retrieved.
The .BackColor is used in the ListImage.Draw method. The .Draw method is simply a wrapper around the ImageList_Draw(himl, i, hdc, x, y, fStyle) API, which draws an imagelist item in the specified device context. The fStyle parameter is used to set the drawing style and only when fStyle = ILD_NORMAL (0) the image is drawn using the background color. You can experiment with this, it speaks for itself.
Note The .BackColor value is passed to the underlying common control using ImageList_SetBkColor() API. 

The .BackColor setting is also used when the ImageList control is used with other controls (that can't be bound to the ImageList control). You can assign the ListImage.Picture object of the ListImage item to the .Picture property of another control. For example, the following code assigns the Picture object of the first ListImage object in a ListImages collection to the Picture property of a newly created StatusBar panel:

Dim pn As Panel
Set pn = sb.Panels.Add() ' Add a new Panel object.
Set pn.Picture = im1.ListImages(1).Picture 

However, how is this Picture created? That is , how are single Pictures  extracted from the image list control? Can this be done by invoking some ImageList_Xxx() API function? The answer is no, the Picture property is a GFA-BASIC 32 specific implementation which uses the .BackColor setting.

The Picture property With .Picture (Get-property) GFA-BASIC allows to create a new bitmap from the image list (and its mask). It creates always a 24 bits DIB memory bitmap to draw the image using ImageList_Draw(). The size of the DIB is ImageWidth x ImageHeight and the background is cleared using the color from .BackColor setting. Then, GFA-BASIC uses the ImageList_Draw() API to draw the specified image using the API background color for the image list (which is also set with .BackColor property!). The net result is a bitmap with a background color .BackColor.
Since the .Picture property returns a 24 bit DIB only, possibly transparent, the new obtained image form the ImageList Ocx might be quite different from what first was added. The .Picture property only returns device independent bitmaps or icons. Any jpg and metafile images are converted to a DIB.  

When you require a transparent image for some other control that accepts an icon use the .ExtractIcon property instead. This will return a real Windows icon resource which is transparent by default.

ImageList Ocx (1)

An ImageList control is a collection of images of the same size and type. An image list control helps you manage a collection of images that are the same size, such as bitmaps or icons. Image lists, which are designed for use with list view and tree view controls, manage images but do not display them directly. In BASIC its use is extended to be repository for other controls as well.
Note Part 2 was published before part 1, so might have read ImageList Ocx (2) before.
The API behind the creation
The windowless ImageList Ocx is a bit different from the image list common control. Although the GFA-BASIC 32 Ocx is created using the API function ImageList_Create(), the underlying image list common control is managed using a second layer of ListImages, another Ocx type. The ListImages object is created when the ImageList Ocx is created and both are initially 'empty'; there is not even a real image list common control. GFA-BASIC 32 doesn't create the underlying image list control before the first picture is added to the list. The reason behind this behavior will be clear when you look at the definition of ImageList_Create(). The image list needs the initial size of the images and most often the size isn't known until the first image is added. 
hIml = ImageList_Create(cx, cy, flags, cInitial, cGrow )

This function creates a new image list common control and returns the handle to the image list if successful. Note that the handle isn't a handle to a window (hIml isn't HWND type).
To be able to create a proper ImageList Ocx, the following parameters and Ocx properties need to be set.
API Meaning ImageList property
cx Define the width and height, in pixels, of each image. .ImageWidth
cy Defines the height of each image .ImageHeight
flags Set of bit flags that specify the type of image list to create.
- use a mask (ILC_MASK) 
- color depth  (ILC_COLORnn)
.ColorFormat (sets color depth and sets ILC_MASK)
cInitial Specify the number of images that the image list initially contains. 1 - Determined by GB32
cGrow Number of images by which the image list can grow when the system needs to make room for new images. 1, 2, or 4 - Determined by GB32
Only three properties determine the type of image list common control is created.
  1. .ImageWidth and .ImageHeight are used to set the cx and cy arguments of the API function. When not specified the first image added to the list determines the width and height of all images (cx and cy).
  2. .ColorFormat is used to set flags API parameter, which specifies the required image type (16 colors, true colors, etc.). Default is device dependent with a mask.
The .UseMaskColor and .MaskColor properties are useful only when the control has a masked bitmap attached. The masked-bitmap is created when the API argument flags includes ILC_MASK (GFA-BASIC default). If the ImageList Ocx doesn't contain a masked bitmap these two properties have no effect!
  • A non-masked image list includes a color bitmap that contains one or more images. This is a wide bitmap containing small bitmaps. When a non-masked image is drawn, it is simply copied into the target device context (DC); no special processing occurs.
  • A masked image list includes two wide bitmaps of equal size. The first is a color bitmap that contains the images; the second is a monochrome bitmap that contains a series of masks (one for each image in the first bitmap). The mask is created by GFA-BASIC 32 and not by Windows, except for icons. Icons contain both a color bitmap and a mask and GFA-BASIC adds directly to the underlying common control.
On output, when an image is retrieved from the ImageList Ocx, the existence of a mask determines how the image is composed. An image can be drawn using ImageList.Draw or extracted using ImageList.Picture or ImageList.ExtractIcon
With a masked image present, the mask is combined with the image itself. This combination produces transparent areas in the bitmap in which the background color of the target DC shows through. More about this is ImageList Ocx (2).
The Picture input Object
The ImageList Ocx only accepts images contained in a Picture or StdPicture object. A Picture Ocx object is a container for a bitmap, icon, jpg, or metafile image. In both VB and GB32 it is not possible to assign any other type of image than a Picture COM type.
There are three ways to obtain a Picture object.    
1. Use LoadPicture() to load an external image file.
2. Use CreatePicture() to create a picture object initialized with a bitmap or icon.
3. Obtain a Picture object from another COM object.

All Picture objects (jpg, bmp, dib, emf) that are added to the ImageList Ocx are provided with custom created mask. The masked image is created by GFA-BASIC using the color from the .MaskColor property, but only when .UseMaskColor is True. .UseMaskColor and .MaskColor determine the transparent color per image.
Adding Pictures – API details
Once you have an image in a Picture object, you can start adding that image to ImageList Ocx. Internally, GB32 has a choice from three possible API functions to add a Picture image: ImageList_Add(), ImageList_AddIcon(), and ImageList_AddMasked() [not used by GB32]. Obviously, GFA-BASIC uses ImageList_AddIcon() when the Picture object holds an icon resource. In all other circumstances it uses the ImageList_Add() API which takes three arguments:
index = ImageList_Add(himl, hbmImage, hbmMask)

When you add an image into the list, GFA-BASIC gives it a mask. If the image is an icon, its internal mask is reused. If it is a bitmap or a metafile, a mask is created. The end result is a collection of icons of the same size. However, all images in an image list are contained in a single, wide bitmap in screen device format. When an image list includes a mask, it also has a monochrome bitmap that contains masks used to draw images transparently (icon style).
Before invoking this function, GFA creates the hbmImage and the hbmMask. The hbmMask is a black bitmap in case .UseMaskColor = False (0).
Usually, the ImageList Ocx is used as an image repository for other Ocx controls. When you attach an ImageList to another control, you don’t need to worry about what gets drawn and how. An image list is a collection of images of the same size, each of which can be referred to by its index or key.
A second blog ImageList Ocx (2) discusses more implementation details.