Author Topic: (Phoenix) Toolbars and how to switch Toolbar-Text at runtime on/off  (Read 5861 times)

0 Members and 1 Guest are viewing this topic.

Offline Theo Gottwald

  • Administrator
  • Hero Member
  • *****
  • Posts: 919
  • User-Rate: +30/-4
    • it-berater
I have discussed this topic with Dominic Mitchell, and the following Text is a part from what he told me.
While the informations are not at all general but partly specific to my actual project, it shows some "How To's " with Toolbars that may be of interest to anyone having to do with toolbars.

--------------------------------------------------------

Toolbar and Phoenix
===================
There is a bug in the Windows toolbar that causes a stack fault when the toolbar has a certain
combination of styles and it is moved, or setting or clearing a style causes it to move.

The following of some of my notes that describe some of the bugs in the Windows toolbar.

Memory leak
-----------
Rapidly creating and destroying toolbars that use the system bitmaps in commctrl.dll
produces a nasty leak in GDI resources.  To make matters worse the resources are
not restored even after the application terminates.  Toolbars that do not use the
system bitmaps do not exhibit this problem.
I cannot think of a single common control supplied by Microsoft that does not
have a plethora of bugs.

CCS_NOPARENTALIGN and dynamic resizing
--------------------------------------
A toolbar with is style may enter a WM_SIZE loop that can lead to a stack fault
when it is dynamically resized.  Use the CCS_NORESIZE style for toolbars
that deeply embedded in for example rebars.  When a toolbar with the CCS_NOPARENTALIGN
style is resized, it walks across the screen.

CCS_NODIVIDER
-------------
Common controls with a divider(CCS_NODIVIDER style not set)
have a tendency to move vertically when their size or position
is changed.  To prevent this behaviour, remove the divider style
before setting size and position properties.

There is a check in the designer that attempts to break out of the runaway recursion, but even
that fails sometimes.

Your modified code
==================

You have three options,
1) Use the original code I sent with a toolbar with the TBSTYLE_FLAT, TBSTYLE_LIST,
   TBSTYLE_EX_MIXEDBUTTONS and CCS_NORESIZE styles.  The drawback with this method is that when the
   buttons have the BTNS_SHOWTEXT style, the text is displayed to the right of the image.

2) Destroy and recreate the toolbar.  This involves the most work because the toolbar state
   will have to be stored somewhere in order for it to be rebuilt.  The toolbar state can be stored
   in the registry or a stream.

3) Vary the size of the toolbar buttons in such a way that the text is hidden or visible.  This allows
   text to be displayed at the bottom or right of the button image.

The rest of this document describes the third option.

Modify layout rules
===================
Open the Layout Manager and delete the rule that produces the following macro:

Code: [Select]
//Action                  Act On                                  Relative To
//-------  ------------------------------------  ----------------------------------------------
// Macro    Part       Widget(First, Last)        Part            Widget             %   Offset
//-------  ------  ----------------------------  ------  -------------------------  ---  ------
  STRETCH, BOTTOM, IDC_MDIFORM1_PAGER1,       0, HEIGHT, IDD_MDIFORM1,               10,      0

Deleting the rule allows the pager to change its size as the height of the toolbar changes.

Toolbar control styles
======================
Only the following styles should be set for the toolbar control:
CCS_NORESIZE
TSTYLE_FLAT

Make sure TBSTYLE_EX_MIXEDBUTTONS is not checked.

Toolbar button styles
=====================
If the button is not a separator, it style should be BTNS_BUTTON, at the very least, it should
not be BTNS_AUTOSIZE or BTNS_SHOWTEXT.

Code to vary size of buttons
============================
Code: [Select]
'-------------------------------------------------------------------------------

FUNCTION Toolbar_ToggleText _
  ( _
  BYVAL hWndToolbar AS DWORD, _ ' handle of toolbar control
  BYVAL fShowText   AS LONG _   ' true = show text, false = hide text
  ) AS LONG

  LOCAL szText            AS ASCIIZ * %MAX_PATH
  LOCAL trc               AS RECT
  LOCAL tsize             AS SIZEL
  LOCAL tbbi              AS TBBUTTONINFO
  LOCAL iButton           AS LONG
  LOCAL cButtons          AS LONG
  LOCAL hWndLabel         AS DWORD
  LOCAL iBtnWithLabel     AS LONG
  LOCAL x                 AS LONG
  LOCAL y                 AS LONG
  LOCAL cxCtrl            AS LONG
  LOCAL cyCtrl            AS LONG
  LOCAL cyOffset          AS LONG
  LOCAL cxyButton         AS LONG
  LOCAL hImgListNormal    AS DWORD
  LOCAL hFont             AS DWORD
  LOCAL cxIcon            AS LONG
  LOCAL cyIcon            AS LONG
  LOCAL hDC               AS DWORD
  LOCAL cxText            AS LONG
  LOCAL cyText            AS LONG
  LOCAL hWndPager         AS DWORD
  LOCAL cxPager           AS LONG
  LOCAL cyPager           AS LONG

  ' If text is being shown
  IF fShowText THEN
    ' Calcualte width and height of buttons
    hImgListNormal = SendMessage(hWndToolbar,  %TB_GETIMAGELIST, 0, 0)
    ImageList_GetIconSize hImgListNormal, BYVAL VARPTR(cxIcon), BYVAL VARPTR(cyIcon)

    hDC = GetDC(hWndToolbar)
    SaveDC hDC
    SelectObject hDC, SendMessage(hWndToolbar, %WM_GETFONT, 0, 0)

    tbbi.cbSize  = SIZEOF(tbbi)
    tbbi.dwMask  = %TBIF_BYINDEX OR %TBIF_STYLE OR %TBIF_COMMAND
    tbbi.pszText = VARPTR(szText)
    tbbi.cchText = %MAX_PATH

    cButtons = SendMessage(hWndToolbar, %TB_BUTTONCOUNT, 0, 0)
    iButton  = 0

    WHILE iButton < cButtons
      szText = ""
      IF SendMessage(hWndToolbar, %TB_GETBUTTONINFO, iButton, BYVAL VARPTR(tbbi)) THEN
        IF (tbbi.fsStyle AND %BTNS_SEP) <> %BTNS_SEP THEN
          SendMessage hWndToolbar, %TB_GETBUTTONTEXT, tbbi.idCommand, BYVAL VARPTR(szText)
          GetTextExtentPoint32 hDC, BYVAL tbbi.pszText, LEN(tbbi.@pszText), tsize
          cxText = MAX(cxText, tsize.cx)
          cyText = MAX(cyText, tsize.cy)
        END IF
      END IF
      INCR iButton
    WEND

    RestoreDC hDC, -1

    SendMessage hWndToolbar, %TB_SETBUTTONSIZE, 0, MAKDWD(cxText + 6, cyIcon + cyText + 9)
  ' Text is being hidden
  ELSE
    ' Let the toolbar set the default size for the buttons
    SendMessage hWndToolbar, %TB_SETBUTTONSIZE, 0, MAKDWD(0, 0)
  END IF

  hWndPager = GetParent(hWndToolbar)
  GetWindowRect hWndPager, trc
  cxPager = trc.nRight - trc.nLeft
  ' Height(6 pixels add to compensate for edges of the pager)
  cyPager = HIWRD(SendMessage(hWndToolbar, %TB_GETBUTTONSIZE, 0, 0)) + 6
  SetWindowPos hWndPager, %NULL, 0, 0, cxPager, cyPager, %SWP_NOZORDER OR %SWP_NOMOVE OR %SWP_DRAWFRAME
  SendMessage hWndPager, %PGM_RECALCSIZE, 0, 0

 ' -------------------------------------------------------
  ' Reposition embedded control(s)
  ' Note: this code assumes that is an embedded control at the
  '       location of button 17.
  hWndLabel = GetDlgItem(hWndToolbar, %IDC_MDIFORM1_TEXTLBL1)
  GetWindowRect hWndLabel, trc
  cxCtrl = trc.nRight - trc.nLeft
  cyCtrl = trc.nBottom - trc.nTop

  ' Get the bounding rectangle of the separator
  iBtnWithLabel = 17
  cyOffset = 1
  SendMessage hWndToolbar, %TB_GETITEMRECT, iBtnWithLabel, BYVAL VARPTR(trc)
  ' Calculate new position of the label
  x = (trc.nLeft + trc.nRight - cxCtrl) \ 2
  y = (trc.nTop + trc.nBottom - cyCtrl) \ 2 + cyOffset
  SetWindowPos hWndLabel, %NULL, x, y, cxCtrl, cyCtrl, %SWP_NOZORDER OR %SWP_DRAWFRAME
  ' -------------------------------------------------------

END FUNCTION
How to invoke code above
========================
Code: [Select]
'-------------------------------------------------------------------------------

FUNCTION MDIForm1_MainMenu1_ViewToolbar _
  ( _
  BYVAL hWnd  AS DWORD _  ' handle of window that owns the menu
  ) AS LONG

  LOCAL hWndPager     AS DWORD
  LOCAL hWndToolbar   AS DWORD
  LOCAL hMenu         AS DWORD
  LOCAL fChecked      AS LONG

  hMenu = GetMenu(hWnd)
  fChecked = ((GetMenuState(hMenu, %IDM_TOOLBAR, %MF_BYCOMMAND) AND %MF_CHECKED) = %MF_CHECKED)

  IF fChecked THEN
    CheckMenuItem hMenu, %IDM_TOOLBAR, %MF_BYCOMMAND OR %MF_UNCHECKED
  ELSE
    CheckMenuItem hMenu, %IDM_TOOLBAR, %MF_BYCOMMAND OR %MF_CHECKED
  END IF

  hWndPager   = GetDlgItem(hWnd, %IDC_MDIFORM1_PAGER1)
  hWndToolbar = GetDlgItem(hWndPager, %IDC_MDIFORM1_TOOLBAR1)

  Toolbar_ToggleText hWndToolbar, NOT fChecked

  ' Update the layout
  SendMessage hWnd, gdwADM_LAYOUT, hWnd, %IDD_MDIFORM1

END FUNCTION
« Last Edit: August 04, 2007, 07:06:09 PM by Theo Gottwald »