Mosaic: The tiles window

We will now create a static control which we will draw the tiles on.

6.1 - Creating the control

We make a new procedure called InitControls that will initialize all the controls on the main window.

.data
  ClassStatic         db     "STATIC",0
.data?
  hStatic             dd     ?
.code
;======================================================================
;                           Init Controls
;======================================================================
InitControls proc hWnd:DWORD
; Create static window for mosaic:
    invoke  CreateWindowEx, WS_EX_CLIENTEDGE, ADDR ClassStatic, NULL,\
            WS_VISIBLE + WS_CHILD + SS_OWNERDRAW    ,\
            15, 55, 220, 220,\
            hWnd, CID_STATIC, hInstance, NULL
    mov     hStatic, eax
ret
InitControls endp

At the start of the file, where the prototypes are, add a prototype for this procedure:

InitControls PROTO STDCALL :DWORD

And in the mosaic.inc file:

CID_STATIC equ 601

The InitControls procedure takes one parameter, hWnd which is the window handle of the main window. The CreateWindowEx function creates a static control with the following styles:

  • Clientedge (window has a sunken border like an edit control)
  • "STATIC" as window class, this creates a static control
  • Child window (WS_CHILD), the window is a child window of the main window
  • Ownerdrawn window (SS_OWNERDRAWN). This means that the program takes care of the drawing of the control.
  • CID_STATIC is the ID of the window, this constant is defined in the include file mosaic.inc
  • Left top position: (15,55), size 220x220

Finally, the window handle is stored in the dword hStatic (defined in .data?)

Now we have to call this procedure:

....
.IF eax==WM_CREATE
invoke InitControls, hWnd
....

This code is in the window procedure (WndProc), the WM_CREATE message is sent on creation of the window. Then initcontrols is called and this procedure creates the static control.

When the program is assembled, this will be the result:

Static frame on window

6.2 - Adding more controls

There will also be a toolbar and a statusbar on the window. You can use CreateWindowEx to create both controls, but there are two functions that simplify creating these controls. They are CreateToolbarEx and CreateStatusWindow. These functions reside in the common controls library, which we have included (includelib comctl32.lib and include comctl32.inc). The library should also be initialized with InitCommonControls but we've already done this.

.data?
 hStatus                dd     ?

.data
 StatusParts            dd      90, 170, -1
 DefaultStatusText      db      "Mosaic 1.0",0

.code
InitControls proc hWnd:DWORD
LOCAL DefaultFont:DWORD
    ;--- Create a static control ---

    ............. static control code here............

    ;--- save default font ---
    invoke  GetStockObject, DEFAULT_GUI_FONT
    mov     DefaultFont, eax

    ; Create statusbar window:
    invoke  CreateStatusWindow, WS_CHILD + WS_VISIBLE,\
             ADDR DefaultStatusText, hWnd, CID_STATUS
    mov     hStatus, eax
    invoke  SendMessage, hStatus, WM_SETFONT, DefaultFont, TRUE
    invoke  SendMessage, hStatus, SB_SETPARTS,3, ADDR StatusParts
...

in mosaic.inc:

CID_STATUS equ 600

There are some changes to the procedure here: There's a new local variable, DefaultFont. GetStockObject returns a standard handle for the default system font. This handle is stored in DefaultFont. The handle doesn't have to be deleted because it's a system handle. Then CreateStatusWindow is called. This function creates a statusbar, with the string DefaultStatusText as default string. Then SendMessage is called twice. The first time, a WM_SETFONT message is sent to the status window to set the font of the control to the default system font. The second time, the status window is divided in 3 part with the SB_SETPARTS message. StatusParts is an array of DWORDs that contain the coordinates of the right edge of each part. -1 means that it's size is maximal.

StatusParts dd 90, 170, -1

As you can see, this is a DWORD array (dd) with the values 90, 170 and -1. These are the coordinates used by SB_SETPARTS. ADDR is used in the parameter to give a pointer to the array as the parameter, and not the value itself.

6.3 - Toolbar

The toolbar will be created with CreateToolbarEx. The Win32 programmer's reference gives this on CreateToolbarEx:

HWND CreateToolbarEx(   HWND hwnd,
                        DWORD ws,
                        UINT wID,
                        int nBitmaps,
                        HINSTANCE hBMInst,
                        UINT wBMID,
                        LPCTBBUTTON lpButtons,
                        int iNumButtons,
                        int dxButton,
                        int dyButton,
                        int dxBitmap,
                        int dyBitmap,
                        UINT uStructSize
);
hwnd
Handle of the parent window
ws
The toolbar window style
wID
Control ID for the toolbar
nBitmaps
Number of button images in the resource bitmap
hBMInst
Instance handle of the aplication that contains the button resource image
wBMID
Resource ID of the buttons bitmap
lpButtons
Pointer to an array of TBBUTTON structures
dxButton/dyButton
Width and height of the buttons on the toolbar
dxBitmap/dyBitmap
Width and height of the images on the buttons.

As you can see, we need two things for the toolbar: A bitmap resource that contains the images for the buttons, and an array of TBBUTTON structures. Each structure in this array contains information for one button.

Creating the resource

Open your resource file again (mosaic.rc) and add the following to the file:

#define BMP_TOOLBAR 801

BMP_TOOLBAR BITMAP DISCARDABLE "resources\\toolbar.bmp"

This will define a new resource ID, 801 to BMP_TOOLBAR. The second line includes the file toolbar.bmp in the resource file as BMP_TOOLBAR. As usual you'll have to define this ID in your include file too:

BMP_TOOLBAR equ 801

The resource you just included is a simple bitmap:

Toolbar image

The bitmap consists of 6 images with size 32x32 pixels. The toolbar control will extract the button image from this bitmap. It can do this automatically because it knows how many images there are and the size of them.

TBBUTTON

Furthermore, CreateToolbarEx wants an array of TBBUTTON structures. The definition of TBBUTTON is:

typedef struct _TBBUTTON {
    int     iBitmap;
    int     idCommand;
    BYTE    fsState;
    BYTE    fsStyle;
    DWORD   dwData;
    int     iString;
} TBBUTTON
iBitmap
zero based index to the button image to use for the button
idCommand
Command ID for the button (sent with WM_COMMAND)
fsState
State flags for the button
fsStyle
Style flags for the button
dwData
Application defined value
iString
zero based index of button string (not used here)

idCommand is an identifier that is sent with the WM_COMMAND message if a button is pressed. We will use the same IDs as the in the menu, this makes pressing a button the same as choosing a menu item. We already defined these IDs in the include file so we can use them directly. We will use three styles here:

TBSTYLE_BUTTON
just a normal pushbutton
TBSTYLE_CHECKGROUP
A group of buttons of which one at a time can be pressed into the 'enabled state'. We use this style for the tree types of displaying the titles: as numbers, as the demo bitmap, or as a user defined bitmap
TBSTYLE_SEP
This is a special style, it doesn't create a button, just a separator. A separator can seperate the button groups, but you can use them whenever you want too.

[in your .data]

ToolbarButtons  TBBUTTON <0, MI_OPENBITMAP, TBSTATE_ENABLED, \
                          TBSTYLE_BUTTON, 0, NULL, NULL>
                TBBUTTON <1, MI_NEWGAME, TBSTATE_ENABLED, \
                          TBSTYLE_BUTTON,0, NULL, NULL>
                TBBUTTON <NULL, NULL, NULL, \
                          TBSTYLE_SEP, NULL, NULL> ;--- separator
                TBBUTTON <2, MI_USESTANDARD, TBSTATE_ENABLED or TBSTATE_CHECKED, \
                          TBSTYLE_CHECKGROUP,0, NULL, NULL>
                TBBUTTON <3, MI_USENUMBERS, TBSTATE_ENABLED, \
                          TBSTYLE_CHECKGROUP,0, NULL, NULL>
                TBBUTTON <4, MI_USEFILE, TBSTATE_ENABLED, \
                          TBSTYLE_CHECKGROUP,0, NULL, NULL>
                TBBUTTON <NULL, NULL, NULL, \
                          TBSTYLE_SEP, NULL, NULL> ;--- separator
                TBBUTTON <5, MI_ABOUT, TBSTATE_ENABLED, \
                          TBSTYLE_BUTTON,0, NULL, NULL>

The brackets <> initialize a structure, each structure member is seperated by a comma. The MI_XXXs are the identifiers used in the menus. The separators don't need any members of the structures except for the style TBSTYLE_SEP. One of the checkgroup buttons has the style TBSTATE_ENABLED, which enables the button by default.

Creating the toolbar

Now it's time to create the toolbar:

[in your .data?]

hToolbar       dd       ?

[in your .code]

invoke  CreateToolbarEx, hWnd, WS_CHILD + WS_VISIBLE + TBSTYLE_FLAT + WS_BORDER,\
            CID_TOOLBAR, 6, hInstance, BMP_TOOLBAR, ADDR ToolbarButtons,\
            8, 32, 32, 32, 32, SIZEOF TBBUTTON
mov     hToolbar, eax
invoke  SendMessage, eax, TB_AUTOSIZE, NULL, NULL

[in mosaic.inc]

CID_TOOLBAR equ 602

This creates a toolbar with:

Style
child window, visible, border and TBSTYLE_FLAT (nice flat toolbar buttons)
Control id
CID_TOOLBAR (602)
Bitmap with button images
BMP_TOOLBAR resource in the module with handle hInstance. The fourth parameter (6) indicates the number of buttons in the bitmap
TBBUTTON structure
ToolbarButtons (ADDR is used to give a pointer to the array)
Buttons
8 buttons in the array of TBBUTTONs, 32x32 pixels. The bitmaps on the buttons are 32x32 pixels too.
TBBUTTON size
SIZEOF TBBUTTON gives the size of the structure.

The toolbar handle is stored in hToolbar (dword variable). Finally, the TB_AUTOSIZE message is sent to the toolbar. This ensures that the control has the proper size to display the buttons and images.

6.4 - Done

If you've done everything correctly, it should look like this:

Toolbar and statusbar

If you messed everything up, here are the current files: mosaic3.zip.