Liberty BASIC News
Safe Registry and Ini File Alternative
Deleting and Renaming Disk Files
Segments and Flushing
Flat Toolbar with Toolips
Translating 32-bit VB API Calls
Event-Driven Programming Concepts
Spotlight on the Community!
ODBC in Liberty BASIC
Hex Viewer
Listing Files Recursively
Registering Hot Keys
Preventing more than 1 instance
Multi-Coloured Text Input Boxes
Images on Buttons and Statictext
Two Demos by David Conner
Before we begin this tutorial, please know that creating a toolbar with tooltips is a fairly complex process. It is possible to do it with great ease with a DLL made especially for the purpose by Dennis McKinney. Get it at the Liberty Belle: http://libertybelle.0catch.com
We can add a real Windows toolbar to our open source Liberty BASIC Editor!
This type of toolbar has flat buttons that appear to raise up when the mouse
hovers over them. We can also add tooltips to the toolbar buttons. Toolbars
and tooltips are part of comctrl32.dll. Here is how we do it, step-by-step:
STEP ONE - create hidden buttons
We need to create some genuine Liberty BASIC buttons so that we have access
to the button event handlers, which are the branch labels. We'll hide these
buttons by giving them a position offscreen and a width and height of zero.
We will never see these buttons in the Open Source Editor, but they are essential
to the operation of the toolbar.
Button #1.hide0, "", [new], UL, -400, -400, 0, 0 Button #1.hide1, "", [open], UL, -400, -400, 0, 0 Button #1.hide2, "", [save], UL, -400, -400, 0, 0 Button #1.hide3, "", [saveas], UL, -400, -400, 0, 0 Button #1.hide4, "", [print], UL, -400, -400, 0, 0 Button #1.hide5, "", [run], UL, -400, -400, 0, 0 Button #1.hide6, "", [debug], UL, -400, -400, 0, 0 Button #1.hide7, "", [maketkn], UL, -400, -400, 0, 0 Button #1.hide8, "", [paint], UL, -400, -400, 0, 0 Button #1.hide9, "", [winfile], UL, -400, -400, 0, 0 Button #1.hide10, "", [notepad], UL, -400, -400, 0, 0 Button #1.hide11, "", [calculator], UL, -400, -400, 0, 0 Button #1.hide12, "", [help], UL, -400, -400, 0, 0 Button #1.hide13, "", [quit], UL, -400, -400, 0, 0
STEP TWO - bitmap for the toolbar
We need a bitmap for our toolbar and it must be created properly. This is
not difficult. For best results, make this bitmap a 16-color bitmap. After
creating the bitmap in your favorite Paint program, be sure to "save
as" and choose the 16-color format. You may instead choose the 256-color
format, but that is the maximum number of colors to use if the toolbar is
to appear correctly.
Make the toolbar bitmap 16 pixels tall. IMPORTANT: fill the background with the traditional, default, Windows lightgray color! This color will appear transparent on the toolbar, so that the button images appear directly on the toolbar, rather than in rectangular boxes. This transparency is the reason we save the bitmap as a 16-color bitmap.
Each button image should be 16 pixels wide and 16 pixels high. Do not leave any space between the button images! If you have two buttons on the toolbar, your toolbar bitmap will be 16 pixels high and 32 pixels wide. If you have four buttons, then it will be 64 pixels wide, and so on.
'do not attempt to create toolbar if bmp is missing
if FileExist(DefaultDir$,"opensrc.bmp")=0 then wait
We'll need a handle to our toolbar bitmap, which we will pass as an argument
to the function that creates the toolbar. We could load the bitmap with Liberty
BASIC's LOADBMP command, but we will instead load it with an API call - LoadImageA.
This function asks for a width and height to give the bitmap, and it will
be loaded at those dimensions. If we use 0 for these arguments, the bitmap
will be loaded at its own default dimensions. The function returns a handle
to the loaded bitmap. We need to be careful when specifying the load flags.
We must use the _LR_LOADFROMFILE flag to tell the function to look for a file
on disk. It is also really important to use the _LR_LOADMAP3DCOLORS flag.
When this flag is used, the function searches the color table for the image
and replaces the following shades of gray with the corresponding 3D color:
Color Replaced with
Dk Gray, RGB(128,128,128) COLOR_3DSHADOW
Gray, RGB(192,192,192) COLOR_3DFACE
Lt Gray, RGB(223,223,223) COLOR_3DLIGHT
This means that the bitmap is loaded to match the system default colors. If a user has an alternate color scheme than the standard Windows desktop colors, and the _LR_LOADMAP3DCOLORS flag is not used, then the images for the buttons will probably appear within their lightgray background boxes. If the flag is used, then the images for the buttons will match the colors in force on the system, giving a very professional look. See issue #100 for more information on bitmap color tables.
The flag for _LR_LOADTRANSPARENT is also used. This flag causes the LoadImageA function to retrieve the color value of the first pixel in the image and replace the corresponding entry in the color table with the default window color (COLOR_WINDOW). All pixels in the image that use that entry become the default window color. This value applies only to images that have corresponding color tables. If the flag includes both the LR_LOADTRANSPARENT and LR_LOADMAP3DCOLORS values, LR_LOADTRANSPARENT takes precedence. However, the color table entry is replaced with COLOR_3DFACE rather than COLOR_WINDOW.
Here is the LoadImageA function:
flags=_LR_LOADFROMFILE or _LR_LOADMAP3DCOLORS _ or _LR_LOADTRANSPARENTCallDLL #user32, "LoadImageA",_ 0 As long,_ 'instance handle, can be null bmp$ As ptr,_ 'file name of bitmap _IMAGE_BITMAP As ulong,_ 'type of image to load 0 As long,_ 'desired width, 0=default 0 As long,_ 'desired height, 0=default flags As long,_ 'load flags hbmpTools As ulong 'handle to loaded bitmap
STEP THREE - define constants and structs
Liberty BASIC recognizes many Windows constants and will subsitute their values
when they are typed with an underscore. The Windows constant for SRCCOPY is
recognized by Liberty BASIC when it is written like this: _SRCCOPY . There
are some Windows constants that are not recognized by Liberty BASIC, and trying
to access them will cause the compiler to halt with an "undefined Windows
constant" error. If this happens, then we must use the actual value of
the constant. Here are some values we must define in order to use a toolbar:
TB.ADDBUTTONS = 1044 TB.SETTOOLTIPS = 1060 TBSTYLE.BUTN = 0 TBSTYLE.FLAT = 2048 TBSTYLE.TOOLTIPS = 256
We will also need a struct that will hold information about the toolbar buttons:
struct TBBUTTON,_ bmpID As long,_ 'index of bitmap cID As long,_ 'command ID State As long,_ 'button state Style As long,_ 'button style dwData As long,_'not used Str As long 'not used
STEP FOUR - get IDs for the hidden buttons
Remember those hidden Liberty BASIC buttons? We use them now. We make a call
to GetWindowLongA with the flag _GWL_ID to get the Windows ID for each of
these buttons. Here are the first two. The GetWindowLongA function returns
the ID of the button. We'll store each ID in a separate variable for use later.
hbutton=hwnd(#1.hide0) CallDLL #user32, "GetWindowLongA",_ hbutton As long,_ type As long,_ hID0 As longhbutton=hwnd(#1.hide1) CallDLL #user32, "GetWindowLongA",_ hbutton As long,_ type As long,_ hID1 As long
STEP FIVE - create the toolbar control
The first thing we must do is fill the TBBUTTON struct. The members are filled
as indicated below. The first toolbar button is initialized when the toolbar
is created. All other buttons are added later:
TBBUTTON.bmpID.struct = 0 'index of first bitmap TBBUTTON.cID.struct = hID0 'ID of first button TBBUTTON.State.struct = 4 'enabled TBBUTTON.Style.struct = TBSTYLE.BUTN 'style TBBUTTON.dwData.struct = 0 'not used TBBUTTON.Str.struct = 0 'not used
Notice the TBBUTTON.cID.struct is given the ID we retrieved for our first hidden Liberty BASIC button. Now, when a user clicks the first toolbar button, our Liberty BASIC branch label event handler for that button will be activated!
We'll set up the style for the toolbar. It will be a child window of our LB window, and it will be visible. We also want the FLAT style of buttons, rather than the raised style, and we'd like our toolbar to have a border. Notice that we are using the TBS.TOOLTIPS style. This allows us to add tooltips to our buttons, for a really professional appearance. Here is the CreateToolbarEx function. Each argument is explained. The function returns the handle to the toolbar.
style=_WS_CHILD Or _WS_VISIBLE Or TBSTYLE.WRAPABLE Or TBSTYLE.FLAT _ Or _WS_BORDER or TBSTYLE.TOOLTIPS uStructSize = Len(TBBUTTON.struct) CallDLL #comctl32, "CreateToolbarEx",_ hMain As long,_ 'parent handle style As long,_ 'window style flags 0 As long,_ 'ID 14 As long,_ 'number of Bitmaps 0 As long,_ 'hBMInst-not used hbmpTools As long,_ 'bitmap handle TBBUTTON As struct,_'toolbar button struct 1 As long,_ 'number of buttons to start 16 As long,_ 'width buttons 16 As long,_ 'height buttons 16 As long,_ 'width bitmaps for buttons 16 As long,_ 'height bitmaps for buttons uStructSize As long,_ hTB As long 'handle to toolbar
STEP SIX - create the toolip control
If we want the toolbar buttons to display tooltips, then we must create the
tooltip control before adding any buttons to the toolbar. We explained tooltips
pretty thoroughly when we first added them to the Open Source Editor in issue
#60, so please refer to that issue for more details. First, we set up some
values that will be needed in creating the tooltip control:
TTF.IDISHWND = 1 TTF.CENTERTIP = 2 TTF.SUBCLASS = 16 TTM.ADDTOOL = 1028 TTM.DELTOOL = 1029 TTS.ALWAYSTIP = 1 TTS.NOPREFIX = 2 style = _WS_POPUP or TTS.NOPREFIX _ or TTS.ALWAYSTIP
Next, we retrieve the instance handle of the parent window:
calldll #user32, "GetWindowLongA", _ h as long, _GWL_HINSTANCE as long,_ hInstance as long
And now we create the tooltip control. It is not a visible control, like a button or textbox, but rather a control that manages the tooltips for us in the background. It knows when the mouse is hovering over a button or other control, and it displays the tooltip for a few seconds, then hides it again. The CreateWindowExA must create a window os "TOOLTIPS_CLASS32" and it returns the handle to the tooltip control.
calldll #user32, "CreateWindowExA",_ _WS_EX_TOPMOST as long,_ "TOOLTIPS_CLASS32" as ptr,_ "" as ptr, style as long,_ _CW_USEDEFAULT as long,_CW_USEDEFAULT as long,_ _CW_USEDEFAULT as long,_CW_USEDEFAULT as long,_ h as long, 0 as long, hInstance as long,_ 0 as long,hwndTT as long
STEP SEVEN - add tooltips to the tooltip control
We need a struct to hold the tooltip information. Here it is:
struct toolinfo, cbSize as long, uFlags as long,_ hwnd as long, uId as long, left as long, top as long,_ right as long, bottom as long, _ hInst as long, lpstrText$ as ptr
We need to fill members of the struct before we add each tooltip. Some things remain the same for each tooltip, so we fill those struct members only once. A change form the previous method of doing tooltips for the Open Source Editor - instead of using the window handle, we fill that struct member with the toolbar handle. We also remove the flag that indicated that the ID for the tooltip is the handle of the control to which it is assigned. Instead of a control ID, we'll use the pixel coordinates of each button to tell the tooltip where it belongs. We need to fill the "top" and "bottom" coordinate members only once, since all buttons are in a horizontal line and share these values:
'THESE STRUCT MEMBERS ONLY NEED TO BE FILLED ONCE: toolinfo.cbSize.struct = len(toolinfo.struct) toolinfo.uFlags.struct = TTF.SUBCLASS toolinfo.hwnd.struct = hTB toolinfo.top.struct=0 'top location on toolbar toolinfo.bottom.struct=22 'bottom location on toolbar
We need to fill some members of the struct differently for each tooltip. Each will have a different caption, and a different left and right location on the toolbar. Each left location is 23 pixels greater than the one preceding it, since that is the "finished" width of the buttons. The right location is 22 pixels greater than the left location for each tooltip/toolbar button. Once we've filled the struct as desired, we send a message to the toolbar with SendMessageA that adds the tooltip.
'THESE STRUCT MEMBERS NEED TO BE FILLED ANEW 'FOR EACH TOOTLIP ADDED: toolinfo.lpstrText$.struct = "New File" toolinfo.left.struct=0 'initial left location toolinfo.right.struct=22 'add 22 to left for right calldll #user32, "SendMessageA", hwndTT as long,_ TTM.ADDTOOL as long, 0 as long,_ toolinfo as struct, re as longtoolinfo.lpstrText$.struct = "Open File" toolinfo.left.struct=23 'add 23 to previous left location toolinfo.right.struct=45 'add 22 to left for right calldll #user32, "SendMessageA", hwndTT as long,_ TTM.ADDTOOL as long, 0 as long,_ toolinfo as struct, re as long (And so on for all tooltips desired.)
STEP EIGHT - add the tooltip control to the toolbar
Remember, we must add the tooltip control before adding buttons to toolbar.
After the tooltip control is created, we added by sending the toolbar a message.
CallDLL #user32, "SendMessageA",_ hTB As long,_ 'toolbar handle TB.SETTOOLTIPS As long,_ 'message to set tooltips hwndTT As long,_ 'handle of our tooltip control 0 As long,_ 'not used result As long
STEP NINE - add buttons to the toolbar
We're almost done! Just as we had to fill the tooltip struct before adding
each tooltip to the control, so must we also fill the toolbar button struct
before adding each toolbar button. It requires the image index for each button.
This is a zero-based index. Our first bitmap image was at index 0, and that
was set when we created the toolbar. The next image is at index 1, and so
on. We also need to fill the struct member that contains the ID of the hidden
Liberty BASIC button that is associated with each toolbar button.
'fill toolbar button struct with new info to add buttons: TBBUTTON.bmpID.struct = 1 'bitmap image index TBBUTTON.cID.struct = hID1 'ID of buttonCallDLL #user32, "SendMessageA",_ hTB As long,_ 'toolbar handle TB.ADDBUTTONS As long,_ 'message to add button 1 As long,_ 'number of buttons to add TBBUTTON As struct,_ 'toolbar button struct r As long
TBBUTTON.bmpID.struct = 2 'bitmap image index TBBUTTON.cID.struct = hID2 'ID of button
CallDLL #user32, "SendMessageA",_ hTB As long,_ 'toolbar handle TB.ADDBUTTONS As long,_ 'message to add button 1 As long,_ 'number of buttons to add TBBUTTON As struct,_ 'toolbar button struct r As long
(And so on for all of the desired buttons.)
Please see the Open Source Editor version 32_04 that is included in the zip archive attached to this newsletter.
WRAPABLE TOOLBARS
The toolbar we created for our editor will not wrap when the window is made
narrower than the toolbar. A wrapable toolbar will add rows and move some
buttons down so that all buttons are visible when the window width becomes
too narrow to display all buttons in a single row. To make a wrapable toolbar,
add the following style bit to the style flag used to create the toolbar:
TBSTYLE.WRAPABLE = 512
For the bar to wrap, we have to sent it a _TB_AUTOSIZE message in our resizehandler
[resize] TB.AUTOSIZE = 1057CallDLL #user32, "SendMessageA",_ hTB As word,_ 'toolbar handle TB.AUTOSIZE As word,_ 'message to resize itself 0 As long,_ '0 0 As long,_ '0 r As long
We haven't made our Open Source Editor toolbar wrapable because it would require a lot more code in the resizehandler, and the method described in this article is already fairly complex! The x, y coordinates for many of the buttons would change when the toolbar wrapped, and we'd need to determine new coordinates and make changes to our tooltips so that they would still display with their associated buttons. This isn't as important for a toolbar with a relatively small number of buttons, but it should be taken into account when creating a toolbar with many buttons.
EASIER TOOLBARS
LB Workshop contains a Toolbar Maker that allows you to select from many standard
button images, or from images of your own. After selecting an image, you may
also specify a branch label for the button and the tooltip text. The Toolbar
Maker automatically saves your toolbar bitmap in 256-color format and creates
the code for the toolbar with tooltips in a sample window, complete with stubs
for all button branches.
http://iquizme.0catch.com/lb/lbw3/lbw3.html
Dennis McKinney has created an extremely versatile toolbar DLL. Here is the way it is described at the Liberty Belle:
-The most versatile toolbar dll available.
-Rewritten to take advantage of LB3 callbacks.
-No extra hidden buttons needed. Cleaner, more efficient LB code.
-Create almost any type of toolbar you need, horizontal, vertical, or wrapable.
-Can be used with floating toolwindows.
-Group different styles of buttons.
-Built-in tooltips. Use one string to create the tips for the whole toolbar.
Grab your copy here:
http://libertybelle.0catch.com/lb3code.htm
Liberty BASIC News
Safe Registry and Ini File Alternative
Deleting and Renaming Disk Files
Segments and Flushing
Flat Toolbar with Toolips
Translating 32-bit VB API Calls
Event-Driven Programming Concepts
Spotlight on the Community!
ODBC in Liberty BASIC
Hex Viewer
Listing Files Recursively
Registering Hot Keys
Preventing more than 1 instance
Multi-Coloured Text Input Boxes
Images on Buttons and Statictext
Two Demos by David Conner