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.
- Only three properties determine the type of image list common control is created.
|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|
- .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).
- .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.
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.