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.
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:
And in the mosaic.inc file:
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:
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.
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:
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:
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:
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:
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]
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?]
[in your .code]
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]
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:
If you messed everything up, here are the current files: mosaic3.zip.