 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Fri Jan 11, 2008 12:52 pm Post subject: |
|
|
TB_SETBUTTONSIZE works
I mistekenly used TB_SETBITMAPSIZE prviously
Thx  _________________
 |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2602 Location: Australia, Qld
|
Posted: Fri Jan 11, 2008 1:55 pm Post subject: |
|
|
I added four buttons with image only, then gave three text.
TB_SETBUTTONSIZE leaves the images centered, so the buttons must be higher to compensate:
TB_SETBUTTONWIDTH updates the button height to fit text (TB_SETBUTTONSIZE not necessary):
 |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Fri Jan 11, 2008 2:29 pm Post subject: |
|
|
Great discovery
This message is good as I don't need to know anything, I can just put some arbitrary values like:
| Code: | | Toolbar_SetButtonWidth(hToolbar, 10, 1000) |
and it works.
Thx dude  _________________
 |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Fri Jan 11, 2008 2:58 pm Post subject: |
|
|
| Quote: | | Its a bit slow, though, even with this small sample menu you created but it shows that it was about SetWinDelay as you resize the main window after every insertion.. |
Its definite that your method suffers cuz of window reposition. When you remove it its fast (its slow regardless SetWinDelay) but window is not vertical.
Vertical toolbar can be also created by using ReBar and some toolbar styles, it will be lot faster, especialy with larger menus.
I will not continue your project as it will be possible with combination of Rebar and Toolbar module once I finish them. I will probably reinvent it then, with just couple lines of code that includes Toolbar.ahk and Rebar.ahk
Another method to speed up your code would be to reposition window in Show function. Then it would work as fast as possible. Thinking about it, its probably better idea then using Rebar for it:
| Code: | TbMenu_Show(tbm)
{
SendMessage, 0x418, 0, 0 ,, ahk_id %tbm% ; TB_BUTTONCOUNT
bc := ErrorLevel
VarSetCapacity(rc,16,0)
SendMessage, 0x427, bc, &rc ,, ahk_id %tbm% ; TB_SETROWS
w := NumGet(rc,8)-NumGet(rc,0)
h := NumGet(rc,12)-NumGet(rc,4)
WinMove, ahk_id %tbm%,, , , w+2, h+2
WinShow, ahk_id %tbm%
} |
I just moved code prior to WinShow from Add function. Much faster.
BTW, I don't know why all icons become grayed when gui looses focus
BTW2, I tried with lot of icons (>20) and it works good and fast after this change. I will definitely reinvent this Toolbar is very flexibile when button position its text, and icon are in question (you can even influence how DrawText works) so menu will be very customizable. _________________
 |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2602 Location: Australia, Qld
|
Posted: Fri Jan 11, 2008 4:51 pm Post subject: |
|
|
| majkinetor wrote: | | (its slow regardless SetWinDelay) | With SetWinDelay,-1 it takes ~5ms per item on my system. That's at least 20x faster than with the default delay. After making the change you suggested, it drops to ~4ms per item... | someone... wrote: | | speed gain wouldn't be significant |
| Quote: | | BTW, I don't know why all icons become grayed when gui looses focus | Nor do I. Maybe it could be prevented with WM_CHANGEUISTATE or similar message.
| Quote: | | I just moved code prior to WinShow from Add function. Much faster. | For that to work as you've posted it, you must've had DetectHiddenWindows On already...
Btw, TbMenu never got to a stage where I considered optimising it... |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Fri Jan 11, 2008 5:22 pm Post subject: |
|
|
| Quote: | | With SetWinDelay,-1 it takes ~5ms per item on my system. | Thats not the case here. I don't know what kind of machine you have but on double core its really slow without changes. Only after change it appears instantious.
| Quote: | |
| Quote: | | Nor do I. Maybe it could be prevented with WM_CHANGEUISTATE or similar message. |
not really some solution....
| Quote: | | For that to work as you've posted it, you must've had DetectHiddenWindows On already... |
lets skip trivial details
| Quote: | | Btw, TbMenu never got to a stage where I considered optimising it... |
Thats obvious. You also said its proof of the concept. I am just sharing my thoughts with you. If that is trouble, I can stop any time... _________________
 |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Fri Jan 11, 2008 8:05 pm Post subject: |
|
|
This is interesting
| The Old New Thing wrote: | Why are there both TBSTYLE_EX_VERTICAL and CCS_VERT?
There are two ways to make a vertical toolbar. You can use the common CCS_VERT style, or you can use the TBSTYLE_EX_VERTICAL extended style which is specific to the toolbar. Why are there two ways of doing the same thing?
Because we messed up.
Whoever created the TBSTYLE_EX_VERTICAL extended style didn't realize that there was already a perfectly good way of specifying a vertical toolbar (namely, CCS_VERT).
What's worse, some vertical behavior is controlled by CCS_VERT and some by TBSTYLE_EX_VERTICAL. So if you want a vertical toolbar, you probably want to set both styles to cover all your bases on Windows XP.
Unfortunately, the story doesn't get any better. Once this mistake was discovered, work was done to try to get the two styles in sync, so that setting one automatically set the other. The idea was to ensure that everybody got consistent behavior instead of getting half-and-half if you, say, turned on CCS_VERT and forgot to turn on TBSTYLE_EX_VERTICAL. But this was itself a failure, because there were some programs that let the two styles fall out of sync on purpose because they liked the half-and-half behavior.
It's a mess. We're sorry.
Pre-emptive snarky comment: "This is why Windows sucks."
|
_________________
 |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2602 Location: Australia, Qld
|
Posted: Sat Jan 12, 2008 1:45 am Post subject: |
|
|
| majkinetor wrote: | | Quote: | | With SetWinDelay,-1 it takes ~5ms per item on my system. | Thats not the case here. I don't know what kind of machine you have but on double core its really slow without changes. | Athlon XP, single core 2.2 GHz. 0.2s for 40 items with SetWinDelay,-1. |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Sat Jan 12, 2008 8:15 pm Post subject: |
|
|
I implemented new version with many updates, basically it supports entire Toolbar API with few final things that I will add later.
Everything works nice except one thing, and I am unable to fix it, no matter what I trie. Its about new feature, customization.
There is new creation flag - ADJUSTABLE - that let the user customize dialog by double clicking toolbar background. It also enables drag and drop of buttons when SHIFT is hold down. This requires user to specify 2 lists - current buttons and available buttons.
Button information is specified as text, each button definition on new line:
Syntax is:
text| icon | state | style
- text - button text, specify - and skip all other parameters to add separator
- icon - 1 based icon number in the image list. Set to 0 to add blank icon. Leave blank to use button position as number (not including separators)
- state - enabled (default), hidden, checked, clicked
- style - dropdown, check, , checkgroup, autosize (a), noprefix. Successive buttons that have checkgroup flag will act as radio buttons. DropDown makes button menus. Autosize makes this button take care of its size (default in LIST toolbar style)
You add 1 or bunch of buttons using AddButtons function. To add all available buttons, just set button definition in global variable ALL for now (buttons that will be availalbe in customization dialog on the left side)
There are number of selfexplantory functions that you can use. To switch text on or off, use SetMaxTextRows(hToolbar on ? 1: 0)
Before adding buttons you must create toolbar using Add function and set its image list using SetImageList. You can still use system catalogs (by default "1L")
I didn't succeded with integrated Tooltips as even with TOOLTIPS flag (Add function) I don't recieve adequate notifications. However its possilbe to achive that functionality by using HOTITEMCHANGE notification wich fires when user is hovering specific button.
This is the picture of the bug that I can't manage to fix. Perhaps I don't see something, so I require some help here...
This happens when you open customization dialog (dbl click toolbar) and move the buttons around (only on toolbar, not in the dialog itself).
About the relevant code:
Everything is happeing in the Toolbar_OnNotify function.
I am am compiling the ALL variable holding all buttons into TBBUTTON array when customization dialog is first open. On succesive notifications via TBN_GETBUTTONINFOA message , I copy the requested item from this array into buffer Toolbar control alocated (lparam + 16 and also copy the buttons text into another buffer (pszText) as requested by TBN_GETBUTTONINFOA.
Reference:
TBN_GETBUTTONINFOA
http://msdn2.microsoft.com/en-us/library/bb787266(VS.85).aspx
NMTOOLBAR
http://msdn2.microsoft.com/en-us/library/bb760473(VS.85).aspx
Sample
http://msdn2.microsoft.com/en-us/library/bb760446(VS.85).aspx#Customizing_Toolbars
To do
- Notification interface
- Save/Restore of toolbar _________________

Last edited by majkinetor on Tue Jan 29, 2008 10:01 am; edited 1 time in total |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Sat Jan 12, 2008 10:05 pm Post subject: |
|
|
Some more tests to present posibilities. Toolbars are added to Static (text) containers instead of main gui. This allows toolbar to be positioned anywhere in the main gui. Container needs to be subclassed to handle WM_NOTIFY messages from toolbar. Currently it doesn't work with flat toolbars correctly, as it shows black background (don't know why, related but doesn't depend on themes here). I put border around statics so you can see containers.
In containers
Vertical (wrapped with fixed button and container width
In Rebar, 2 vertical toolbars
Toolbar is added into rebar also using Static container as for some reason it doesn't accept toolbar control directly (don't know why)
Here are scripts to play with. _________________
 |
|
| Back to top |
|
 |
skwire
Joined: 18 Jan 2006 Posts: 150 Location: Conway, Arkansas
|
Posted: Sat Jan 12, 2008 10:43 pm Post subject: |
|
|
| This is really fantastic, majkinetor. Thank you for putting this together and continuing to work on it. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2602 Location: Australia, Qld
|
Posted: Sun Jan 13, 2008 4:37 am Post subject: |
|
|
Very nice work!
| majkinetor wrote: | | This is the picture of the bug that I can't manage to fix. Perhaps I don't see something, so I require some help here... | On my system the squares show as Japanese characters. It seems the toolbar is messing up (maybe deleting the text or invalidating the pointer), referencing garbage where the text used to be.
The solution is to let the toolbar manage all strings, rather than giving it string pointers.
Require hToolbar as a parameter for Toolbar_compileButtons, then instead of
| Code: | VarSetCapacity(buf, 64*cnt)
tp := &Buf
...
DllCall("lstrcpyn", "uint", tp, "uint", &a1, "int", 64)
| use | Code: | VarSetCapacity(buf, StrLen(a1)+1, 0), buf:=a1
tp:=DllCall("SendMessage","uint",hToolbar,"uint",0x41C,"uint",0,"uint",&buf) ; TB_ADDSTRING
| Buf must be double-NULL-terminated, hence the "+1, 0". TB_ADDSTRING returns the new index of the string within the string pool.
It seems there aren't any messages for removing or changing a string in the string pool... hopefully I'm overlooking something. Well, I suppose you wouldn't commonly want to change a button's text.
Perhaps you could instead update the strings in response to TBN_TOOLBARCHANGE. |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Sun Jan 13, 2008 12:36 pm Post subject: |
|
|
Hej, that works
But I wonder
I wonder, perhaps it is seeing my text pointers as sting pull index for some reason...
| Quote: | | The iString member can return either a string pointer or an index. You can use the err! bad xref: _win32_IS_INTRESOURCE [rid not found (_win32_IS_INTRESOURCE).] macro to determine which is returned. |
| Quote: | | It seems there aren't any messages for removing or changing a string in the string pool... hopefully I'm overlooking something. Well, I suppose you wouldn't commonly want to change a button's text. |
I wouldn't like such limitation as you can use toolbar unconventionaly in many scenarios. You can still change text with SetButtonInfo, but that doesn't change the string pool :
| Code: | | Toolbar_SetButtonInfo( hToolbar, 1, "button 1") |
This will change the text for the button1 but old text "btn1" will be returned in customization dialog.
| Quote: | | Text is commonly assigned to buttons when they are added to a toolbar by specifying the index of a string in the toolbar's string pool. If you use a TB_SETBUTTONINFO to assign new text to a button, it will permanently override the text from the string pool. You can change the text by calling TB_SETBUTTONINFO again, but you cannot reassign the string from the string pool. |
So, its not possible to change the string pull. Changing the text is possible, but not in customization dialog, wich is minor limitation IMO. However, customization dialog can be changed by chaging the ALL global variable in sync with changing the button's text . So in the above statement, along with SetButonInfo call there should be call that sets "button 1" as text for the first button in ALL var, and customization dlg will be updated well.
I would be more lucky to made previous solution working, but as I can't, I will switch to this one. I wonder how that MSDN sample works without problems, I was totaly following it...
| Quote: | | Perhaps you could instead update the strings in response to TBN_TOOLBARCHANGE. |
Yes, definitely an option.
Thank you Lex, you were very helpfull as always.
BTW, In the meantime, I discovered that using entire GUI as container for the toolbar (and then SetParent) doesn't introduce transparaency problem (black background). Adding GUI strate from the AHK makes parent GUI unable to focus, but I guess it can be fixed by constructing the container from the bottom up using RegisterClass and CWEx. _________________
 |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2602 Location: Australia, Qld
|
Posted: Sun Jan 13, 2008 1:33 pm Post subject: |
|
|
| majkinetor wrote: | | I wonder, perhaps it is seeing my text pointers as sting pull index for some reason... | Sounds like a possibility.
| majkinetor wrote: | | Quote: | | The iString member can return either a string pointer or an index. You can use the err! bad xref: _win32_IS_INTRESOURCE [rid not found (_win32_IS_INTRESOURCE).] macro to determine which is returned. |
| ?
| My sane copy of MSDN wrote: | | The iString member can return either a string pointer or an index. You can use the IS_INTRESOURCE macro to determine which is returned. |
| Code: | | #define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16) == 0) |
| majkinetor wrote: | | Adding GUI strate from the AHK makes parent GUI unable to focus, | Sounds like what happens when you SetParent() without removing WS_POPUP and adding WS_CHILD... |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Sun Jan 13, 2008 1:59 pm Post subject: |
|
|
| Quote: | | My sane copy of MSDN wrote: |
ROFLMAO.
I was wondering wht the heck is that...
| Quote: | | Sounds like what happens when you SetParent() without removing WS_POPUP and adding WS_CHILD... |
Good, I tried that, but I probably messed it up in WinSpector...
So now it works
Sample:
| Code: | #SingleInstance, force
SetBatchLines, -1
#Include ShowMenu.ahk
Gui, +LastFound +LabelMyGui
; Gui, Add, text, hwndhS1 w400 h50 border
; Gui, Add, text, hwndhS2 w50 h300 border
; Gui, Add, text, hwndhS3 x100 y100 w100 h100 border
;
; Subclass( hS1, "MyWindowProc" )
; Subclass( hS2, "MyWindowProc" )
; Subclass( hS3, "MyWindowProc" )
hwnd := WinExist()
Gui, Show , w400 h250 ;set gui width & height (mandatory)
hIL := IL_Create(5, 0, 1)
Gui, 2:+LastFound -Caption
Gui, 2:Show ,w300 h100 Hide NoActivate
h := WInExist()
hToolbar := Toolbar_Add(h)
Toolbar_SetImageList(hToolbar)
btns =
(LTrim
btn1
btn2
btn3
btn3
btn1
btn2
btn3
btn3
)
Gui 2:Show, x50 y100 w300 h100 NoActivate
Toolbar_AddButtons(hToolbar, btns)
DllCall("SetParent", "uint", h, "uint", hwnd)
WinSet, Style, -0x80000000, ahk_id %h% ; WS_POPUP=0x80000000
WinSet, Style, +0x40000000, ahk_id %h% ; WS_CHILD=0x40000000
Gui, show
return
MyWindowProc(hwnd, uMsg, wParam, lParam){
if uMsg = 0x4E
return Toolbar_OnNotify(wparam, lparam)
return DllCall("CallWindowProcA", "UInt", A_EventInfo, "UInt", hwnd, "UInt", uMsg, "UInt", wParam, "UInt", lParam)
}
;------------------------------------------------------------------------------
;Compile btn definition into binary array. Return number of button.
; aBTN - compiled btn array
; Buf - buffer for btn text
; btns - textual btn def
;
Toolbar_compileButtons(ByRef aBTN, ByRef buf, btns) {
static BTNS_SEP=1, BTNS_CHECK =2, BTNS_CHECKGROUP = 6, BTNS_DROPDOWN = 8, BTNS_A=16, BTNS_AUTOSIZE = 16, BTNS_NOPREFIX = 32, BTNS_SHOWTEXT = 64
static TBSTATE_CHECKED=1, TBSTATE_ENABLED=4, TBSTATE_HIDDEN=8, TBSTATE_GRAYED =16, TBSTATE_PRESSED =5, TBSTATE_CLICKED=6, TBSTATE_WRAP=32, TBSTATE_ELLIPSES=0x40
static TB_ADDBUTTONSA = 0x414, TB_AUTOSIZE=0x421
StringReplace, _, btns, `n, , UseErrorLevel
cnt := ErrorLevel + 1
sep := 0
VarSetCapacity(aBTN, 20*cnt, 0)
VarSetCapacity(buf, 64*cnt)
tp := &Buf
loop, parse, btns, `n
{
a1:=a2:=a3:=a4:=""
StringSplit, a, A_LoopField, |
hstate := TBSTATE_ENABLED
loop, parse, a3, %A_Tab%%A_Space%, %A_Tab%%A_Space%
{
ifEqual, A_LoopField,,continue
hstate |= TBSTATE_%A_LOOPFIELD%
}
hstyle := A_LoopField = "-" ? BTNS_SEP : BTNS_SHOWTEXT
if (hstyle = BTNS_SEP)
sep+=1
loop, parse, a4, %A_Tab%%A_Space%
{
ifEqual, A_LoopField,,continue
hstyle |= BTNS_%A_LOOPFIELD%
}
if a2 is not Integer ;if user doesn't specify icon, use A_Index, but don't count separators
a2 := A_Index - sep
o := &aBTN + 20*(A_Index-1)
DllCall("lstrcpyn", "uint", tp, "uint", &a1, "int", 64)
NumPut(a2-1, o+0, 0) ;id
NumPut(A_Index, o+0, 4) ;id
NumPut(hstate, o+0, 8, "Char")
NumPut(hStyle, o+0, 9, "Char")
NumPut(tp, o+0, 16)
tp += StrLen(a1)+1
}
return cnt
}
Toolbar_onNotify(wparam, lparam) {
local hwnd, id, code, txt
static NM_CLICK=-2, TBN_DROPDOWN = -710, TBN_HOTITEMCHANGE = -713, TBN_BEGINADJUST=-703, TBN_GETBUTTONINFOA=-700, TBN_QUERYINSERT=-706, TBN_QUERYDELETE=-707, TBN_ENDADJUST=-704, TBN_DELETINGBUTTON=-715, TBN_RESET=-705, TBN_TOOLBARCHANGE=-708
static cus, cntAll
;NMHDR
hwnd := NumGet(lparam+0) ;control sending the message - this toolbar
; idFrom := NumGet(lparam+4) ; and its ID
code := NumGet(lparam+8) - 4294967296
;TOOLBAR
iItem := NumGet(lparam+12)
if (code = NM_CLICK) and (iItem != 4294967295){
txt := Toolbar_GetButtonInfo( hwnd, iItem )
tooltip %txt% : %iItem% click
return
}
if (code = TBN_DROPDOWN){
ShowMenu("[1]`ntext1`ntext2`ntext31111111111", "", "mnu")
return
}
if (code = TBN_HOTITEMCHANGE){
iItem := NumGet(lparam+16)
; tooltip % Toolbar_GetButtonInfo(htoolbar, iItem)
return
}
TBB := lparam + 16
if (code = TBN_GETBUTTONINFOA){
if !cus {
cntAll := Toolbar_compileButtons(aBTNS, NBUF, all ), cus := true
}
if (iItem = cntAll) ;iItem is position, not identifier
return
o := &aBTNS + 20*iItem, TBB := lparam +16
DllCall("MSVCRT\memcpy", "UInt", TBB, "UInt", o, "uint", 20) ;copy the compiled item into notification struct
;Customization dialog uses this buffer to get text to display.
;It doesn't use TBB+16, probably because text can be some longer tooltip, if you specified TOOLTIPS flag.
DllCall("MSVCRT\memcpy", "UInt", NumGet(TBB+24), "UInt", NumGet(o+16), "uint", NumGet(TBB+20) )
return TRUE
}
;Return at least one TRUE here to show the dialog, if the dialog is openinig
;When the dialog is open, it affects btn addition
if (code= TBN_QUERYINSERT) {
return TRUE
; if !cus
; return TRUE
; else {
; ; tooltip %iItem%
; return TRUE
; }
}
;existing items can not be deleted if TRUE is not returned here
if (code= TBN_QUERYDELETE) {
; if iItem in 0,1,2 ; prevent 0,1,2 id's to be deleted
; return FALSE
return TRUE
}
if (code=TBN_ENDADJUST){
return
}
}
F12::
stop := 1
; HexView(&NBUF, 100)
; hexview(NumGet(o+16), 20)
return
Toolbar_AddButtons(hToolbar, btns){
static TB_ADDBUTTONSA = 0x414, TB_AUTOSIZE=0x421
cnt := Toolbar_compileButtons(aBTN, TextBuf, btns)
SendMessage, TB_ADDBUTTONSA, cnt, &aBTN ,, ahk_id %hToolbar%
SendMessage, TB_AUTOSIZE, , ,,ahk_id %hToolbar%
}
Toolbar_Add(hGui, style="WRAPABLE FLAT ADJUSTABLE") {
static TOOLBARCLASSNAME = "ToolbarWindow32"
static WS_CHILD := 0x40000000, WS_VISIBLE := 0x10000000, WS_CLIPSIBLINGS = 0x4000000, WS_CLIPCHILDREN = 0x2000000
static TBSTYLE_EX_DRAWDDARROWS = 0x1, TBSTYLE_EX_HIDECLIPPEDBUTTONS=0x10, TBSTYLE_EX_MIXEDBUTTONS=0x8 ;extended styles
static TBSTYLE_WRAPABLE = 0x200, TBSTYLE_FLAT = 0x800, TBSTYLE_LIST=0x1000, TBSTYLE_TOOLTIPS=0x100, TBSTYLE_TRANSPARENT = 0x8000
static TBSTYLE_BORDER=0x800000, TBSTYLE_ADJUSTABLE = 0x20
static init, TB_BUTTONSTRUCTSIZE=0x41E, TB_SETEXTENDEDSTYLE := 0x454, TB_SETUNICODEFORMAT := 0x2005
hStyle := 0
loop, parse, style, %A_Tab%%A_Space%, %A_Tab%%A_Space%
{
ifEqual, A_LoopField,,continue
hStyle |= A_LoopField+0 ? A_LoopField : TBSTYLE_%A_LoopField%
}
if !init {
OnMessage(WM_NOTIFY := 0x4E, "Toolbar_onNotify"), init := true
}
hToolbar := DllCall("CreateWindowEx"
, "uint", 0
, "str", TOOLBARCLASSNAME
, "uint", 0
, "uint", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | hStyle
, "uint", 0, "uint", 0, "uint", 0, "uint", 0
, "uint", hGui
, "uint", 0
, "uint", 0
, "uint", 0, "Uint")
ifEqual, hToolbar, 0, return "Err: can't create toolbar"
SendMessage, TB_BUTTONSTRUCTSIZE, 20, 0, , ahk_id %hToolbar%
SendMessage, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS|TBSTYLE_EX_MIXEDBUTTONS, , ahk_id %hToolbar%
SendMessage, TB_SETUNICODEFORMAT, 0, 0, , ahk_id %hToolbar% ;set to ANSI
return hToolbar
}
Toolbar_SetImageList(hToolbar, hIL="1L"){
static TB_SETIMAGELIST=0x430, TB_LOADIMAGES=0x432, TB_SETBITMAPSIZE=0x420
if hIL is Integer
SendMessage, TB_SETIMAGELIST, 0, hIL, ,ahk_id %hToolbar%
else {
size := SubStr(hIL,2,1)="L" ? 24:16, cat := (SubStr(hIL, 1,1)-1)*4 + (size=16 ? 0:1)
Toolbar_SetBitmapSize(hToolbar, size, size)
SendMessage, TB_LOADIMAGES, cat, -1,,ahk_id %hToolbar%
}
return ErrorLevel
}
;----------------------------------------------------------------------------------------------
;Function: SetButtonInfo
; Set button information
;
;Parameters:
; hToolbar - HWND of the toolbar
; id - Button identification (currently equal to buttons position)
; text - Text to set for the button. If "" text will not be changed. If "-" text wil be removed (the same as omiting both text and state parameters)
; state - List of button states to set, separated by white space. See bellow.
;
; Button states:
; CHECKED, ENABLED, HIDDEN, GRAYED, PRESSED, CLICKED
;
; Returns:
; Nonzero if successful, or zero otherwise.
;
Toolbar_SetButtonInfo(hToolbar, id, text="", state="", width=""){
static TB_SETBUTTONINFO=0x442, TBIF_TEXT=2, TBIF_STATE=4, TBIF_SIZE=0x40, TB_AUTOSIZE=0x421
static TBSTATE_CHECKED=1, TBSTATE_ENABLED=4, TBSTATE_HIDDEN=8, TBSTATE_GRAYED=16, TBSTATE_PRESSED=5, TBSTATE_CLICKED=6, TBSTATE_WRAP=32
hstate := 0
loop, parse, state, %A_Tab%%A_Space%, %A_Tab%%A_Space%
{
ifEqual, A_LoopField,,continue
hstate |= TBSTATE_%A_LOOPFIELD%
}
mask := 0
mask |= text != "" ? TBIF_TEXT : 0
mask |= state!= "" ? TBIF_STATE : 0
mask |= width!= "" ? TBIF_SIZE : 0
if text = -
text =
if (state text = "")
mask := TBIF_TEXT, text := ""
VarSetCapacity(BI, 32, 0)
NumPut(32, BI, 0)
NumPut(mask, BI, 4)
NumPut(hstate, BI, 16, "Char")
NumPut(width, BI, 18, "Short")
NumPut(&text, BI, 24)
SendMessage, TB_SETBUTTONINFO, id, &BI, ,ahk_id %hToolbar%
res := ErrorLevel
SendMessage, 0x421, , ,,ahk_id %hToolbar% ;autosize
return res
}
;----------------------------------------------------------------------------------------------
;Function: SetButtons
; Set all butons at once using textual definition
;
;Parameters:
; hToolbar - HWND of the toolbar
; info - Textual definition of buttons info. For each button there should be line containg *text|state list* where
; both _text_ and _state list_ are optional. You can also use "-" to skip button (the same as empty line).
; If you omit this parameter text and state for each button will be cleared
;
Toolbar_SetButtons(hToolbar, info=""){
if info=
{
Loop, % Toolbar_GetButtonCount(hToolbar)
Toolbar_SetButtonInfo(hToolbar, A_Index, "-", "ENABLED" )
return
}
loop, parse, info, `n,
{
if j := InStr(A_LoopField, "|")
state := SubStr(A_LoopField, j+1)
else state := "enabled"
txt := SubStr(A_LoopField, 1, j ? j-1 : 99)
ifEqual txt, -, continue
Toolbar_SetButtonInfo(hToolbar, A_Index, txt, state)
}
}
;----------------------------------------------------------------------------------------------
;Function: GetButtonInfo
; Get button information
;
;Parameters:
; hToolbar - HWND of the toolbar
; id - ID of the button (currently the same as position)
; info - What kind of info to return - text (default) or state
;
Toolbar_GetButtonInfo(hToolbar, id, info="text"){
; static TB_GETBUTTONINFO=0x441, TBIF_TEXT=2, TBIF_STATE=4
static TB_GETBUTTONTEXT=0x42D, TB_GETSTATE=0x412
static S1 = "CHECKED", S4 = "ENABLED", S8 ="HIDDEN", S16="GRAYED", S5="PRESSED", S6="CLICKED"
if info=text
{
VarSetCapacity( buf, 128 )
SendMessage, TB_GETBUTTONTEXT,id,&buf,,ahk_id %hToolbar%
ifEqual, Errorlevel, 4294967295, return
VarSetCapacity( buf, -1 )
return buf
}
else if info=state
{
SendMessage, TB_GETSTATE,id,,,ahk_id %hToolbar%
state = S%ErrorLevel%
state := %state%
return state
}
; mask := TBIF_TEXT
; if info = state
; mask := TBIF_STATE
;
;
; VarSetCapacity(BI, 32, 0)
; NumPut(32, BI, 0)
; NumPut(mask, BI, 4)
; SendMessage, TB_GETBUTTONINFO, id, &BI, ,ahk_id %hToolbar%
; if ErrorLevel=4294967295
; return "Err: can't get button info"
;
; if info=text
; return NumGet(BI, 8)
}
;----------------------------------------------------------------------------------------------
;Function: GetButtonCount
; Get count of buttons on the toolbar
;
;Parameters:
; hToolbar - HWND of the toolbar
;
;Returns:
; Count
Toolbar_GetButtonCount(hToolbar) {
static TB_BUTTONCOUNT = 0x418
SendMessage, TB_BUTTONCOUNT, , , ,ahk_id %hToolbar%
return ErrorLevel
}
;----------------------------------------------------------------------------------------------
;Function: DeleteButton
; Delete button from the toolbar
;
;Parameters:
; hToolbar - HWND of the toolbar
; idx - 1-based position of the button
;
;Returns:
; TRUE if successful, or FALSE otherwise.
;
Toolbar_DeleteButton(hToolbar, idx=1) {
static TB_DELETEBUTTON = 0x416
SendMessage, TB_DELETEBUTTON, idx-1, , ,ahk_id %hToolbar%
return ErrorLevel
}
;----------------------------------------------------------------------------------------------
;Function: GetRect
; Get button rectangle
;
;Parameters:
; hToolbar - HWND of the toolbar
; id - Button id
;
;Returns:
; String with 4 rect values, separated by space
;
Toolbar_GetRect(hToolbar, id) {
static TB_GETRECT=0x433, RECT
VarSetCapacity(RECT, 16)
SendMessage, TB_GETRECT, id,&RECT, ,ahk_id %hToolbar%
IfEqual, ErrorLevel, 0, return "Err: can't get rect"
return NumGet(RECT, 0) " " NumGet(RECT, 4) " " NumGet(RECT, 8) " " NumGet(RECT, 12)
}
;----------------------------------------------------------------------------------------------
;Function: GetRows
; Get number of toolbar rows
;
;Parameters:
; hToolbar - HWND of the toolbar
;
;Returns:
; Count
;
Toolbar_GetRows(hToolbar) {
static TB_GETROWS=0x428
SendMessage, TB_GETROWS,,,,ahk_id %hToolbar%
return ErrorLevel-1
}
;doesn't work correctly for some reason
Toolbar_SetPadding(hToolbar, cx=6, cy=7) {
static TB_SETPADDING=0x457
SendMessage, TB_SETPADDING,0,(cx<<16)+cy,,ahk_id %hToolbar%
return ErrorLevel>>16 " " ErrorLevel & 0xFFFF
}
mnu:
Toolbar_SetButtonInfo(hToolbar, id, A_ThisMenuItem)
return
Toolbar_SetDrawTextFlags(hToolbar) {
static TB_SETDRAWTEXTFLAGS = 0x446
}
;Returns nonzero if successful, or zero otherwise.
Toolbar_SetMaxTextRows(hToolbar, iMaxRows=0) {
static TB_SETMAXTEXTROWS = 0x43C
SendMessage, TB_SETMAXTEXTROWS,iMaxRows,,,ahk_id %hToolbar%
res := ErrorLevel
SendMessage,0x421,,,,ahk_id %hToolbar% ;autoresize
return res
}
Toolbar_SetMetrics(hToolbar, xPad="", yPad="", xButtonMargin="", yButtonMargin="", xMargin="", yMargin=""){
VarSetCapacity(met,32,0), NumPut(32,met)
NumPut( ((xPad yPad)!="" ? 1:0)
| ((xMargin yMargin)!="" ? 2:0)
| ((xButtonMargin yButtonMargin)!="" ? 4:0), met, 4)
NumPut(xPad,met,8), NumPut(yPad,met,12)
NumPut(0,met,16), NumPut(yMargin,met,20)
NumPut(xButtonMargin,met,24), NumPut(yButtonMargin,met,28)
DllCall("SendMessage","uint",hToolbar,"uint",0x466,"uint",0,"uint",&met) ; TB_SETMETRICS
DllCall("SendMessage","uint",hToolbar,"uint",0x42F,"int",xMargin,"uint",0) ; TB_SETINDENT
}
;Returns TRUE if successful, or FALSE otherwise.
Toolbar_SetButtonSize(hToolbar, x=0, y=0) {
static TB_SETBUTTONSIZE = 0x41F
SendMessage, TB_SETBUTTONSIZE, 0,(y<<16) | x,,ahk_id %hToolbar%
SendMessage, 0x421, , ,,ahk_id %hToolbar% ;autosize
}
;Returns nonzero if successful, or zero otherwise.
Toolbar_SetButtonWidth(hToolbar, cxMin, cxMax ){
static TB_SETBUTTONWIDTH=0x43B
SendMessage, TB_SETBUTTONWIDTH, 0,(cxMin<<16) | cxMax,,ahk_id %hToolbar%
return Errorlevel
}
Toolbar_SetBitmapSize(hToolbar, x, y ) {
SendMessage, 0x420,0,(x<<16)+y, , ahk_id %hToolbar%
}
Toolbar_AutoSize(hToolbar){
SendMessage,0x421,,,,ahk_id %hToolbar% ;autoresize
}
;-------------------------------------------------------------------------------------------------------------------
;Group: Example
;
;> Gui, +LastFound
;> hwnd := WinExist()
;> Gui, Show ,w280 h200 ;set gui width & height (mandatory)
;> hToolbar := Toolbar_Add(hwnd)
;-------------------------------------------------------------------------------------------------------------------
;Group: About
; o Ver 1.0 b1 by majkinetor. See http://www.autohotkey.com/forum/topic27382.html
; o Toolbar Reference at MSDN: <http://msdn2.microsoft.com/en-us/library/bb760435(VS.85).aspx>
; o Licenced under Creative Commons Attribution-Noncommercial <http://creativecommons.org/licenses/by-nc/3.0/>.
MyGuiClose:
MyGuiEscape:
exitapp
return
;-------------------------------------------------------------------------------------
; Function: Subclass
; Helper function to subclass control
;
; Parameters:
; hCtrl - handle to control
; func - window procedure
; cbOpt - callback options, by default ""
;
Subclass(hCtrl, func, cbOpt="") {
oldProc := DllCall("GetWindowLong", "uint", hCtrl, "uint", -4)
ifEqual, oldProc, 0, return 0
WndProc := RegisterCallback(func, cbOpt, 4, oldProc)
ifEqual, WndProc, , return 0
return DllCall("SetWindowLong", "UInt", hCtrl, "Int", -4, "Int", WndProc, "UInt")
} |
It still makes sense to create container window from ground up just to avod using new gui, every time you need this feature (and its obviously very useful) _________________
 |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|