AutoHotkey Community

It is currently May 26th, 2012, 2:37 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 31 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject:
PostPosted: January 11th, 2008, 12:52 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
TB_SETBUTTONSIZE works
I mistekenly used TB_SETBITMAPSIZE prviously :roll:

Thx :D

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2008, 1:55 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
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:
Image

TB_SETBUTTONWIDTH updates the button height to fit text (TB_SETBUTTONSIZE not necessary):
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2008, 2:29 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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 :D

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2008, 2:58 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2008, 4:51 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
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
:roll:
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...


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2008, 5:22 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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:
:roll:

:roll:


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...

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2008, 8:05 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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."

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2008, 1:45 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
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. :lol: 0.2s for 40 items with SetWinDelay,-1.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2008, 8:15 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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...
Image
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

_________________
Image


Last edited by majkinetor on January 29th, 2008, 10:01 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2008, 10:05 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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
Image

Vertical (wrapped with fixed button and container width
Image

In Rebar, 2 vertical toolbars
Image

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.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2008, 10:43 pm 
Offline

Joined: January 18th, 2006, 7:39 am
Posts: 274
Location: Conway, Arkansas
This is really fantastic, majkinetor. Thank you for putting this together and continuing to work on it.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 13th, 2008, 4:37 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Very nice work! :D
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. :lol: 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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 13th, 2008, 12:36 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
Hej, that works :D

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.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 13th, 2008, 1:33 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
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.
:shock: ?
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...


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 13th, 2008, 1:59 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
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")
}


Image

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)

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 31 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 20 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group