Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
toolbar.c
Package: shell.rar [view]
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 223k
Category:
Windows Kernel
Development Platform:
Visual C++
- /*
- ** Toolbar.c
- **
- ** This is it, the incredibly famous toolbar control. Most of
- ** the customization stuff is in another file.
- */
- #include "ctlspriv.h"
- #include "toolbar.h"
- #include "image.h"
- #include <limits.h>
- #include "apithk.h"
- #define __IOleControl_INTERFACE_DEFINED__ // There is a conflich with the IOleControl's def of CONTROLINFO
- #include "shlobj.h"
- #ifdef MAINWIN
- #include <mainwin.h>
- void TBSetHotItemWithoutNotification(PTBSTATE ptb, int iPos, DWORD dwReason);
- extern void TruncateString(char *sz, int cch);
- #endif
- #define TBP_ONRELEASECAPTURE (WM_USER + 0x500)
- #define TBIMAGELIST
- // these values are defined by the UI gods...
- #define DEFAULTBITMAPX 16
- #define DEFAULTBITMAPY 15
- #define LIST_GAP (g_cxEdge * 2)
- #define DROPDOWN_GAP (g_cxEdge * 2)
- #define CX_TOP_FUDGE (g_cxEdge * 2)
- #define SMALL_DXYBITMAP 16 // new dx dy for sdt images
- #define LARGE_DXYBITMAP 24
- #define DEFAULTBUTTONX 24
- #define DEFAULTBUTTONY 22
- // the insert mark is 6 pixels high/wide depending on horizontal or vertical mode...
- #define INSERTMARKSIZE 6
- const int g_dxButtonSep = 8;
- const int s_xFirstButton = 0; // was 8 in 3.1
- #define s_dxOverlap 0 // was 1 in 3.1
- #define USE_MIXED_BUTTONS(ptb) (((ptb)->dwStyleEx & TBSTYLE_EX_MIXEDBUTTONS) && ((ptb)->ci.style & TBSTYLE_LIST))
- #define BTN_NO_SHOW_TEXT(ptb, ptbb) (!(ptb)->nTextRows || (USE_MIXED_BUTTONS(ptb) && !((ptbb)->fsStyle & BTNS_SHOWTEXT)))
- #define BTN_IS_AUTOSIZE(ptb, ptbb) (((ptbb)->fsStyle & BTNS_AUTOSIZE) || (USE_MIXED_BUTTONS(ptb) && !((ptbb)->fsStyle & BTNS_SEP)))
- #define DRAW_MONO_BTN(ptb, state) (!(state & TBSTATE_ENABLED) || ((ptb->ci.style & WS_DISABLED) && ptb->ci.iVersion >= 5))
- // Globals - since all of these globals are used durring a paint we have to
- // take a criticial section around all toolbar paints. this sucks.
- //
- const UINT wStateMasks[] = {
- TBSTATE_ENABLED,
- TBSTATE_CHECKED,
- TBSTATE_PRESSED,
- TBSTATE_HIDDEN,
- TBSTATE_INDETERMINATE,
- TBSTATE_MARKED
- };
- #define TBISSTRINGPTR(iString) (((iString) != -1) && (!IS_INTRESOURCE(iString)))
- #define TBDraw_State(ptbdraw) ((ptbdraw)->tbcd.nmcd.uItemState)
- LRESULT CALLBACK ToolbarWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
- void TBOnButtonStructSize(PTBSTATE ptb, UINT uStructSize);
- BOOL SetBitmapSize(PTBSTATE ptb, int width, int height);
- int AddBitmap(PTBSTATE ptb, int nButtons, HINSTANCE hBMInst, UINT_PTR wBMID);
- void TBBuildImageList(PTBSTATE ptb);
- BOOL GetInsertMarkRect(PTBSTATE ptb, LPRECT lpRect, BOOL fHorizMode);
- LPTSTR TB_StrForButton(PTBSTATE ptb, LPTBBUTTONDATA pTBButton);
- UINT TBGetDrawTextFlags(PTBSTATE ptb, UINT uiStyle, LPTBBUTTONDATA);
- BOOL TBGetMaxSize( PTBSTATE ptb, LPSIZE lpsize );
- void TBGetItem(PTBSTATE ptb,LPTBBUTTONDATA ptButton, LPNMTBDISPINFO ptbdi);
- #define GT_INSIDE 0x0001
- #define GT_MASKONLY 0x0002
- BOOL GrowToolbar(PTBSTATE ptb, int newButWidth, int newButHeight, UINT flags);
- //Pager Control Functions
- LRESULT TB_OnScroll(PTBSTATE ptb, LPNMHDR pnm);
- LRESULT TB_OnPagerControlNotify(PTBSTATE ptb,LPNMHDR pnm);
- void TBAutoSize(PTBSTATE ptb);
- LRESULT TB_OnCalcSize(PTBSTATE ptb, LPNMHDR pnm);
- #define TBInvalidateImageList(ptb) ((ptb)->fHimlValid = FALSE)
- #define TBHasStrings(ptb) ((ptb)->nStrings || (ptb)->fNoStringPool)
- #ifdef DEBUG
- #if 0
- void _InvalidateRect(HWND hwnd, LPRECT prc, BOOL fInval)
- {
- if (!(GetAsyncKeyState(VK_SHIFT) < 0) )
- InvalidateRect(hwnd, prc, fInval);
- }
- void _RedrawWindow(HWND hwnd, LPRECT prc, HANDLE hrgn, UINT uFlags)
- {
- if (!(GetAsyncKeyState(VK_SHIFT) < 0) )
- RedrawWindow(hwnd, prc, hrgn, uFlags);
- }
- void _SetWindowPos(HWND hwnd, HWND hwnd2, int x, int y, int cx, int cy, UINT uFlags)
- {
- if (GetAsyncKeyState(VK_SHIFT) < 0)
- uFlags &= ~( SWP_FRAMECHANGED);
- SetWindowPos(hwnd, hwnd2, x, y, cx, cy, uFlags);
- }
- #define InvalidateRect(hwnd, prc, fInval) _InvalidateRect(hwnd, prc, fInval)
- #define RedrawWindow(hwnd, prc, hrgn, uFlags) _RedrawWindow(hwnd, prc, hrgn, uFlags)
- #define SetWindowPos(hwnd, hwnd2, x, y, cx, cy, uFlags) _SetWindowPos(hwnd, hwnd2, x, y, cx, cy, uFlags)
- #endif
- #endif
- __inline BOOL TB_IsDropDown(LPTBBUTTONDATA ptbb)
- {
- BOOL fRet = (ptbb->fsStyle & (BTNS_DROPDOWN | BTNS_WHOLEDROPDOWN));
- return fRet;
- }
- __inline BOOL TB_HasDDArrow(PTBSTATE ptb, LPTBBUTTONDATA ptbb)
- {
- BOOL fRet = (((ptb->dwStyleEx & TBSTYLE_EX_DRAWDDARROWS) &&
- (ptbb->fsStyle & BTNS_DROPDOWN)) ||
- (ptbb->fsStyle & BTNS_WHOLEDROPDOWN));
- return fRet;
- }
- __inline BOOL TB_HasSplitDDArrow(PTBSTATE ptb, LPTBBUTTONDATA ptbb)
- {
- // If the button is both BTNS_DROPDOWN and BTNS_WHOLEDROPDOWN,
- // BTNS_WHOLEDROPDOWN wins.
- BOOL fRet = ((ptb->dwStyleEx & TBSTYLE_EX_DRAWDDARROWS) &&
- (ptbb->fsStyle & BTNS_DROPDOWN) &&
- !(ptbb->fsStyle & BTNS_WHOLEDROPDOWN));
- return fRet;
- }
- __inline BOOL TB_HasUnsplitDDArrow(PTBSTATE ptb, LPTBBUTTONDATA ptbb)
- {
- BOOL fRet = (ptbb->fsStyle & BTNS_WHOLEDROPDOWN);
- return fRet;
- }
- __inline BOOL TB_HasTopDDArrow(PTBSTATE ptb, LPTBBUTTONDATA ptbb)
- {
- BOOL fRet = (!(ptb->ci.style & TBSTYLE_LIST) &&
- TB_HasUnsplitDDArrow(ptb, ptbb) &&
- (ptb->nTextRows > 0) && TB_StrForButton(ptb, ptbb));
- return fRet;
- }
- BOOL TBIsHotTrack(PTBSTATE ptb, LPTBBUTTONDATA ptButton, UINT state)
- {
- BOOL fHotTrack = FALSE;
- if ((ptb->ci.style & TBSTYLE_FLAT) && (&ptb->Buttons[ptb->iHot]==ptButton))
- fHotTrack = TRUE;
- // The following is in place to prevent hot tracking during the following conds:
- // - drag & drop toolbar customization
- // - when the mouse capture is on a particular button-press.
- // This does _not_ drop out of the loop because we don't want to break update
- // behavior; thus we'll have a little flickering on refresh as we pass over
- // these buttons.
- if (!(state & TBSTATE_PRESSED) && (GetKeyState (VK_LBUTTON) < 0) &&
- GetCapture() == ptb->ci.hwnd)
- {
- fHotTrack = FALSE;
- }
- if (!fHotTrack && (ptb->iPressedDD == ptButton - ptb->Buttons))
- fHotTrack = TRUE;
- return fHotTrack;
- }
- UINT StateFromCDIS(UINT uItemState)
- {
- UINT state = 0;
- if (uItemState & CDIS_CHECKED)
- state |= TBSTATE_CHECKED;
- if (uItemState & CDIS_SELECTED)
- state |= TBSTATE_PRESSED;
- if (!(uItemState & CDIS_DISABLED))
- state |= TBSTATE_ENABLED;
- if (uItemState & CDIS_MARKED)
- state |= TBSTATE_MARKED;
- if (uItemState & CDIS_INDETERMINATE)
- state |= TBSTATE_INDETERMINATE;
- return state;
- }
- UINT CDISFromState(UINT state)
- {
- UINT uItemState = 0;
- // Here are the TBSTATE - to - CDIS mappings:
- //
- // TBSTATE_CHECKED = CDIS_CHECKED
- // TBSTATE_PRESSED = CDIS_SELECTED
- // !TBSTATE_ENABLED = CDIS_DISABLED
- // TBSTATE_MARKED = CDIS_MARKED
- // TBSTATE_INDETERMINATE = CDIS_INDETERMINATE
- //
- // Hot tracked item = CDIS_HOT
- //
- if (state & TBSTATE_CHECKED)
- uItemState |= CDIS_CHECKED;
- if (state & TBSTATE_PRESSED)
- uItemState |= CDIS_SELECTED;
- if (!(state & TBSTATE_ENABLED))
- uItemState |= CDIS_DISABLED;
- if (state & TBSTATE_MARKED)
- uItemState |= CDIS_MARKED;
- if (state & TBSTATE_INDETERMINATE)
- uItemState |= CDIS_INDETERMINATE;
- return uItemState;
- }
- void FlushToolTipsMgrNow(PTBSTATE ptb);
- void TB_ForceCreateTooltips(PTBSTATE ptb)
- {
- if (ptb->ci.style & TBSTYLE_TOOLTIPS && !ptb->hwndToolTips)
- {
- TOOLINFO ti;
- // don't bother setting the rect because we'll do it below
- // in TBInvalidateItemRects;
- ti.cbSize = sizeof(ti);
- ti.uFlags = TTF_IDISHWND;
- ti.hwnd = ptb->ci.hwnd;
- ti.uId = (UINT_PTR)ptb->ci.hwnd;
- ti.lpszText = 0;
- #ifndef UNIX
- ptb->hwndToolTips = CreateWindow(c_szSToolTipsClass, NULL,
- WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- ptb->ci.hwnd, NULL, HINST_THISDLL, NULL);
- #else
- ptb->hwndToolTips = CreateWindowEx( WS_EX_MW_UNMANAGED_WINDOW, c_szSToolTipsClass, NULL,
- WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- ptb->ci.hwnd, NULL, HINST_THISDLL, NULL);
- #endif
- if (ptb->hwndToolTips) {
- int i;
- NMTOOLTIPSCREATED nm;
- CCSetInfoTipWidth(ptb->ci.hwnd, ptb->hwndToolTips);
- SendMessage(ptb->hwndToolTips, TTM_ADDTOOL, 0,
- (LPARAM)(LPTOOLINFO)&ti);
- nm.hwndToolTips = ptb->hwndToolTips;
- CCSendNotify(&ptb->ci, NM_TOOLTIPSCREATED, &nm.hdr);
- // don't bother setting the rect because we'll do it below
- // in TBInvalidateItemRects;
- ti.uFlags = 0;
- ti.lpszText = LPSTR_TEXTCALLBACK;
- for (i = 0; i < ptb->iNumButtons; i++) {
- if (!(ptb->Buttons[i].fsStyle & BTNS_SEP)) {
- ti.uId = ptb->Buttons[i].idCommand;
- SendMessage(ptb->hwndToolTips, TTM_ADDTOOL, 0,
- (LPARAM)(LPTOOLINFO)&ti);
- }
- }
- FlushToolTipsMgrNow(ptb);
- }
- }
- }
- void TBRelayToToolTips(PTBSTATE ptb, UINT wMsg, WPARAM wParam, LPARAM lParam)
- {
- TB_ForceCreateTooltips(ptb);
- if (ptb->hwndToolTips) {
- RelayToToolTips(ptb->hwndToolTips, ptb->ci.hwnd, wMsg, wParam, lParam);
- }
- }
- LRESULT ToolbarDragCallback(HWND hwnd, UINT code, WPARAM wp, LPARAM lp)
- {
- PTBSTATE ptb = (PTBSTATE)GetWindowInt(hwnd, 0);
- LRESULT lres;
- switch (code)
- {
- case DPX_DRAGHIT:
- if (lp)
- {
- POINT pt;
- int item;
- pt.x = ((POINTL *)lp)->x;
- pt.y = ((POINTL *)lp)->y;
- MapWindowPoints(NULL, ptb->ci.hwnd, &pt, 1);
- item = TBHitTest(ptb, pt.x, pt.y);
- if (0 <= item && item < ptb->iNumButtons)
- lres = (LRESULT)ptb->Buttons[item].idCommand;
- else
- lres = (LRESULT)-1;
- }
- else
- lres = -1;
- break;
- case DPX_GETOBJECT:
- lres = (LRESULT)GetItemObject(&ptb->ci, TBN_GETOBJECT, &IID_IDropTarget, (LPNMOBJECTNOTIFY)lp);
- break;
- case DPX_SELECT:
- if ((int)wp >= 0)
- {
- NMTBHOTITEM nmhi;
- nmhi.idNew = (int) wp;
- if (!CCSendNotify(&ptb->ci, TBN_DRAGOVER, &nmhi.hdr))
- {
- SendMessage(ptb->ci.hwnd, TB_MARKBUTTON, wp,
- MAKELPARAM((lp != DROPEFFECT_NONE), 0));
- }
- }
- lres = 0;
- break;
- default:
- lres = -1;
- break;
- }
- return lres;
- }
- int TBMixedButtonHeight(PTBSTATE ptb, int iIndex)
- {
- int iHeight;
- LPTBBUTTONDATA ptbb = &(ptb->Buttons[iIndex]);
- if (ptbb->fsStyle & BTNS_SHOWTEXT) // text and icon
- iHeight = max(ptb->iDyBitmap, ptb->dyIconFont);
- else // icon, no text
- iHeight = ptb->iDyBitmap;
- return iHeight;
- }
- int TBMixedButtonsHeight(PTBSTATE ptb)
- {
- int i;
- int iHeightMax = 0;
- int iHeight;
- ASSERT(ptb->ci.style & TBSTYLE_LIST);
- ASSERT(USE_MIXED_BUTTONS(ptb));
- for (i = 0; i < ptb->iNumButtons; i++) {
- iHeight = TBMixedButtonHeight(ptb, i);
- iHeightMax = max(iHeightMax, iHeight);
- }
- return iHeightMax;
- }
- int HeightWithString(PTBSTATE ptb, int h)
- {
- if (USE_MIXED_BUTTONS(ptb))
- {
- int hMixed = TBMixedButtonsHeight(ptb);
- return (max(h, hMixed));
- }
- else if (ptb->ci.style & TBSTYLE_LIST)
- return (max(h, ptb->dyIconFont));
- else if (ptb->dyIconFont)
- return (h + ptb->dyIconFont + 1);
- else
- return (h);
- }
- int TBGetSepHeight(PTBSTATE ptb, LPTBBUTTONDATA pbtn)
- {
- ASSERT(pbtn->fsStyle & BTNS_SEP);
- if (ptb->ci.style & (CCS_VERT | TBSTYLE_FLAT) )
- return pbtn->DUMMYUNION_MEMBER(cxySep);
- else
- return pbtn->DUMMYUNION_MEMBER(cxySep) * 2 / 3;
- }
- UINT TBWidthOfString(PTBSTATE ptb, LPTBBUTTONDATA ptbb, HDC hdc)
- {
- UINT uiWidth = 0;
- LPTSTR pstr = TB_StrForButton(ptb, ptbb);
- if (pstr)
- {
- HDC hdcCreated = NULL;
- HFONT hOldFont;
- UINT uiStyle;
- RECT rcText = {0,0,1000,10};
- if (!hdc)
- {
- hdcCreated = GetDC(ptb->ci.hwnd);
- hdc = hdcCreated;
- }
- hOldFont = SelectObject(hdc, ptb->hfontIcon);
- uiStyle = DT_CALCRECT | TBGetDrawTextFlags(ptb, 0, ptbb);
- DrawText(hdc, pstr, -1, &rcText, uiStyle);
- uiWidth += rcText.right;
- SelectObject(hdc, hOldFont);
- if (hdcCreated)
- ReleaseDC(ptb->ci.hwnd, hdcCreated);
- }
- return uiWidth;
- }
- // TBDDArrowAdjustment(ptb, ptbb): the amount by which we change the width of
- // this button to accomodate the drop-down arrow. not necessarily the same as
- // ptb->dxDDArrowChar.
- int TBDDArrowAdjustment(PTBSTATE ptb, LPTBBUTTONDATA ptbb)
- {
- int iAdjust = 0;
- if (TB_HasDDArrow(ptb, ptbb))
- {
- // If a whole dd, non-autosize button, then we'll just use the standard
- // button width which ought to have room for this button (i.e., return 0).
- if (!TB_HasTopDDArrow(ptb, ptbb) || BTN_IS_AUTOSIZE(ptb, ptbb))
- {
- iAdjust += (WORD)ptb->dxDDArrowChar;
- if (TB_HasUnsplitDDArrow(ptb, ptbb))
- {
- // subtract off a bit since there won't be a border
- // around dd arrow part of this button
- iAdjust -= 2 * g_cxEdge;
- if (ptbb->iBitmap != I_IMAGENONE)
- {
- // nudge over a bit more to overlap bitmap border padding
- iAdjust -= g_cxEdge;
- }
- }
- if (TB_HasTopDDArrow(ptb, ptbb))
- {
- // If string width >= icon width + iAdjust, then no need
- // to add extra space for the arrow.
- if ((int)TBWidthOfString(ptb, ptbb, NULL) >= ptb->iDxBitmap + iAdjust)
- iAdjust = 0;
- }
- }
- }
- return max(iAdjust, 0);
- }
- int TBWidthOfButton(PTBSTATE ptb, LPTBBUTTONDATA pButton, HDC hdc)
- {
- RECT rc;
- if (BTN_IS_AUTOSIZE(ptb, pButton)) {
- // if they've set this button for autosize, calculate it and cache
- // it in cx
- if (BTN_NO_SHOW_TEXT(ptb, pButton)) {
- pButton->cx = 0;
- goto CalcIconWidth;
- }
- if (pButton->cx == 0) {
- UINT uiStringWidth = TBWidthOfString(ptb, pButton, hdc);
- pButton->cx = (WORD) ptb->xPad + uiStringWidth;
- if (uiStringWidth) {
- // Since we have a string for this button, we need to add
- // some padding around it.
- if ((ptb->ci.style & TBSTYLE_LIST) && TB_HasSplitDDArrow(ptb, pButton))
- pButton->cx += (WORD) ptb->iDropDownGap;
- else
- pButton->cx += 2 * g_cxEdge;
- }
- CalcIconWidth:
- if (pButton->iBitmap != I_IMAGENONE) {
- if (ptb->ci.style & TBSTYLE_LIST) {
- pButton->cx += ptb->iDxBitmap + ptb->iListGap;
- if (BTN_NO_SHOW_TEXT(ptb, pButton))
- pButton->cx += g_cxEdge * 2;
- }
- else {
- // Use wider of string width (pButton->cx so far) and bitmap width.
- pButton->cx = max(pButton->cx, ptb->iDxBitmap + ptb->xPad);
- }
- }
- pButton->cx += (USHORT)TBDDArrowAdjustment(ptb, pButton);
- }
- }
- if (pButton->cx) {
- return (int)pButton->cx;
- } else if (pButton->fsStyle & BTNS_SEP) {
- if (ptb->ci.style & CCS_VERT) {
- GetWindowRect(ptb->ci.hwnd, &rc);
- return RECTWIDTH(rc);
- } else {
- // Compat: Corel (Font navigator) expects the separators to be
- // 8 pixels wide. So do not return pButton->cxySep here, since
- // that can be calculated differently depending on the flat style.
- //
- // No. owner draw items are added by specifying separator, and
- // the iBitmap width which is then copied down to cxySep.
- // the preserving of size for corel needs to be done at that point.
- return pButton->DUMMYUNION_MEMBER(cxySep);
- }
- } else if (!(TBSTYLE_EX_VERTICAL & ptb->dwStyleEx)) {
- return ptb->iButWidth + TBDDArrowAdjustment(ptb, pButton);
- } else {
- return ptb->iButWidth;
- }
- }
- UINT TBGetDrawTextFlags(PTBSTATE ptb, UINT uiStyle, TBBUTTONDATA* ptbb)
- {
- if (ptb->nTextRows > 1)
- uiStyle |= DT_WORDBREAK | DT_EDITCONTROL;
- else
- uiStyle |= DT_SINGLELINE;
- if (ptb->ci.style & TBSTYLE_LIST)
- {
- uiStyle |= DT_LEFT | DT_VCENTER | DT_SINGLELINE;
- }
- else
- {
- uiStyle |= DT_CENTER;
- }
- uiStyle &= ~(ptb->uDrawTextMask);
- uiStyle |= ptb->uDrawText;
- if (ptbb->fsStyle & BTNS_NOPREFIX)
- uiStyle |= DT_NOPREFIX;
- #ifndef KEYBOARDCUES
- // This flag tells User's DrawText/Ex NOT to show the prefixes at all
- // when rendering. This only works on NT5.
- if (!ptb->fShowPrefix && g_bRunOnNT5)
- #else
- if (CCGetUIState(&(ptb->ci)) & UISF_HIDEACCEL)
- #endif
- {
- uiStyle |= DT_HIDEPREFIX;
- }
- return uiStyle;
- }
- BOOL TBRecalc(PTBSTATE ptb)
- {
- TEXTMETRIC tm = {0};
- int i;
- HDC hdc;
- int cxMax = 0, cxMask, cy;
- HFONT hOldFont=NULL;
- if (ptb->fRedrawOff) {
- // redraw is off; defer recalc until redraw is turned back on
- ptb->fRecalc = TRUE;
- return TRUE; // The recalc "succeeded" - actual work will happen later
- }
- ptb->dyIconFont = 0;
- if (!TBHasStrings(ptb) || !ptb->nTextRows ) {
- cxMax = ptb->iDxBitmap;
- cxMask = cxMax;
- } else {
- SIZE size = {0};
- LPCTSTR pstr;
- RECT rcText = {0,0,0,0};
- int cxExtra = ptb->xPad;
- ptb->iButWidth = 0;
- hdc = GetDC(ptb->ci.hwnd);
- if (!hdc)
- return(FALSE);
- if (ptb->hfontIcon)
- hOldFont = SelectObject(hdc, ptb->hfontIcon);
- GetTextMetrics(hdc, &tm);
- if (ptb->nTextRows)
- ptb->dyIconFont = (tm.tmHeight * ptb->nTextRows) +
- (tm.tmExternalLeading * (ptb->nTextRows - 1)); // add an edge ?
- if (ptb->ci.style & TBSTYLE_LIST)
- cxExtra += ptb->iDxBitmap + ptb->iListGap;
- // default to the image size...
- cxMax = ptb->iDxBitmap;
- // walk strings to find max width
- for (i = 0; i < ptb->iNumButtons; i++)
- {
- if (ptb->Buttons[i].fsState & TBSTATE_HIDDEN)
- continue;
- if (BTN_IS_AUTOSIZE(ptb, &ptb->Buttons[i]))
- ptb->Buttons[i].cx = 0;
- pstr = TB_StrForButton(ptb, &ptb->Buttons[i]);
- if (pstr)
- {
- if ( ptb->ci.iVersion < 5 )
- {
- // we used to use GetTextExtentPoint instead of DrawText. This function would include the width
- // of the "&" character if it was present. As a result, it returned larger values and thus created
- // wider buttons. Without this extra fudge certain buttons will be about 6 pixels too narrow.
- GetTextExtentPoint(hdc, pstr, lstrlen(pstr), &size);
- }
- else
- {
- // wordbreak is not allowed in the calcrect w/ singleline
- UINT uiStyle = DT_CALCRECT | DT_SINGLELINE | (TBGetDrawTextFlags(ptb, 0, &ptb->Buttons[i]) & ~DT_WORDBREAK);
- RECT rcTemp = {0,0,0,0};
- rcTemp.bottom = ptb->dyIconFont;
- DrawText(hdc, pstr, -1, &rcTemp, uiStyle);
- size.cx = RECTWIDTH(rcTemp);
- size.cy = RECTHEIGHT(rcTemp);
- // BUGBUG: size.cy stuff is fishy -- last one wins
- }
- }
- else
- {
- size.cx = 0;
- }
- if (TB_HasTopDDArrow(ptb, &ptb->Buttons[i])) {
- int iBmpWithArrow = CX_TOP_FUDGE + ptb->iDxBitmap + ptb->dxDDArrowChar;
- size.cx = max(size.cx, iBmpWithArrow);
- }
- else if ((ptb->dwStyleEx & TBSTYLE_EX_VERTICAL) &&
- TB_HasDDArrow(ptb, &ptb->Buttons[i])) {
- // for vertical toolbars, buttons with drop-down arrows
- // are drawn with the same width as normal buttons, so
- // we need to figure them into our max width calculation.
- size.cx += ptb->dxDDArrowChar;
- }
- if (cxMax < size.cx)
- cxMax = size.cx;
- }
- // if cxMax is less than the iButMinWidth - dxBitmap (if LIST) then
- // cxMax = iButMinWidth
- if (ptb->iButMinWidth && (ptb->iButMinWidth > (cxMax + cxExtra)))
- cxMax = ptb->iButMinWidth - cxExtra;
- cxMask = cxMax;
- // Is the cxMax + dxBitmap (if LIST) more than the max width ?
- if (ptb->iButMaxWidth && (ptb->iButMaxWidth < (cxMax + cxExtra)))
- {
- int cyMax = 0;
- int cxTemp = 0;
- cxMax = ptb->iButMaxWidth - cxExtra;
- // But leave cxMask at its old value since AUTOSIZE buttons
- // are exempt from button truncation. This exemption is a bug,
- // but IE4 shipped that way so we're stuck with it. (You can
- // tell it's a bug because we go ahead and flip TBSTATE_ELLIPSIS
- // even on AUTOSIZE buttons, only to "forget" about the ellipsis
- // in TBWidthOfString().)
- // walk strings to set the TBSTATE_ELLIPSES
- for (i = 0; i < ptb->iNumButtons; i++)
- {
- BOOL fEllipsed = FALSE;
- UINT uiStyle;
- if (ptb->Buttons[i].fsState & TBSTATE_HIDDEN)
- continue;
- if (BTN_NO_SHOW_TEXT(ptb, &ptb->Buttons[i]))
- pstr = NULL;
- else
- {
- pstr = TB_StrForButton(ptb, &ptb->Buttons[i]);
- uiStyle = DT_CALCRECT | TBGetDrawTextFlags(ptb, 0, &ptb->Buttons[i]);
- }
- if (pstr)
- {
- int cxMaxText;
- if ((ptb->dwStyleEx & TBSTYLE_EX_VERTICAL) &&
- TB_HasDDArrow(ptb, &ptb->Buttons[i]))
- {
- // if a drop-down button on a vertical toolbar,
- // need to make space for drop-down arrow
- cxMaxText = cxMax - ptb->dxDDArrowChar;
- }
- else
- {
- cxMaxText = cxMax;
- }
- // DrawText doesn't like it when cxMaxText <= 0
- cxMaxText = max(cxMaxText, 1);
- rcText.bottom = ptb->dyIconFont;
- rcText.right = cxMaxText;
- DrawText(hdc, pstr, -1, &rcText, uiStyle);
- if (ptb->nTextRows > 1)
- {
- // width is width of text plus width we might
- // have lopped off for drop-down arrow
- int cx = rcText.right + (cxMax - cxMaxText);
- if (cx > cxTemp)
- {
- // this is our new multiline text hack max
- cxTemp = cx;
- }
- fEllipsed = (BOOL)(rcText.bottom > ptb->dyIconFont);
- }
- else
- fEllipsed = (BOOL)(rcText.right > cxMaxText);
- if (cyMax < rcText.bottom)
- cyMax = rcText.bottom;
- }
- if (fEllipsed)
- ptb->Buttons[i].fsState |= TBSTATE_ELLIPSES;
- else
- ptb->Buttons[i].fsState &= ~TBSTATE_ELLIPSES;
- }
- if (cxTemp && (ptb->nTextRows > 1 ))
- cxMax = cxTemp;
- // Set the text height to the tallest text, with the top end being the number
- // of rows specified by MAXTEXTROWS
- if (ptb->dyIconFont > cyMax)
- ptb->dyIconFont = cyMax;
- }
- else
- {
- for (i = 0; i < ptb->iNumButtons; i++)
- ptb->Buttons[i].fsState &= ~TBSTATE_ELLIPSES;
- if ((ptb->nTextRows) && ptb->iNumButtons && (ptb->dyIconFont > size.cy))
- ptb->dyIconFont = size.cy;
- }
- if (ptb->iButMinWidth && (ptb->iButMinWidth > (cxMax + cxExtra)))
- cxMax = ptb->iButMinWidth - cxExtra;
- if (hOldFont)
- SelectObject(hdc, hOldFont);
- ReleaseDC(ptb->ci.hwnd, hdc);
- }
- //
- // Need to call GrowToolbar twice, once to grow the mask, and again
- // to grow the buttons. (Yes, this is sick.)
- //
- cy = HeightWithString(ptb, ptb->iDyBitmap);
- if (!GrowToolbar(ptb, max(cxMax, cxMask), cy, GT_INSIDE | GT_MASKONLY))
- return(FALSE);
- return(GrowToolbar(ptb, cxMax, cy, GT_INSIDE));
- }
- BOOL TBChangeFont(PTBSTATE ptb, WPARAM wParam, HFONT hFont)
- {
- LOGFONT lf;
- BOOL fWasFontCreated = ptb->fFontCreated;
- if ((wParam != 0) && (wParam != SPI_SETICONTITLELOGFONT) && (wParam != SPI_SETNONCLIENTMETRICS))
- return(FALSE);
- if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0))
- return(FALSE);
- if (!hFont) {
- if (!(hFont = CreateFontIndirect(&lf)))
- return(FALSE);
- ptb->fFontCreated = TRUE;
- } else {
- ptb->fFontCreated = FALSE;
- }
- if (ptb->hfontIcon && fWasFontCreated)
- DeleteObject(ptb->hfontIcon);
- ptb->hfontIcon = hFont;
- return(TBRecalc(ptb));
- }
- void TBSetFont(PTBSTATE ptb, HFONT hFont, BOOL fInval)
- {
- TBChangeFont(ptb, 0, hFont);
- if (fInval)
- InvalidateRect(ptb->ci.hwnd, NULL, TRUE);
- }
- HWND WINAPI CreateToolbarEx(HWND hwnd, DWORD ws, UINT wID, int nBitmaps,
- HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
- int iNumButtons, int dxButton, int dyButton,
- int dxBitmap, int dyBitmap, UINT uStructSize)
- {
- HWND hwndToolbar = CreateWindow(c_szToolbarClass, NULL, WS_CHILD | ws,
- 0, 0, 100, 30, hwnd, (HMENU)wID, HINST_THISDLL, NULL);
- if (hwndToolbar)
- {
- PTBSTATE ptb = (PTBSTATE)GetWindowInt(hwndToolbar, 0);
- TBOnButtonStructSize(ptb, uStructSize);
- if ((dxBitmap && dyBitmap && !SetBitmapSize(ptb, dxBitmap, dyBitmap)) ||
- (dxButton && dyButton && !SetBitmapSize(ptb,dxButton, dyButton)))
- {
- //!!!! do we actually need to deal with this?
- DestroyWindow(hwndToolbar);
- hwndToolbar = NULL;
- goto Error;
- }
- AddBitmap(ptb, nBitmaps, hBMInst, wBMID);
- TBInsertButtons(ptb, (UINT)-1, iNumButtons, (LPTBBUTTON)lpButtons, TRUE);
- // ptb may be bogus now after above button insert
- }
- Error:
- return hwndToolbar;
- }
- /* This is no longer declared in COMMCTRL.H. It only exists for compatibility
- ** with existing apps; new apps must use CreateToolbarEx.
- */
- HWND WINAPI CreateToolbar(HWND hwnd, DWORD ws, UINT wID, int nBitmaps, HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons, int iNumButtons)
- {
- // old-style toolbar, so no divider.
- return CreateToolbarEx(hwnd, ws | CCS_NODIVIDER, wID, nBitmaps, hBMInst, wBMID,
- lpButtons, iNumButtons, 0, 0, 0, 0, sizeof(OLDTBBUTTON));
- }
- #pragma code_seg(CODESEG_INIT)
- BOOL InitToolbarClass(HINSTANCE hInstance)
- {
- WNDCLASS wc;
- if (!GetClassInfo(hInstance, c_szToolbarClass, &wc))
- {
- wc.lpfnWndProc = (WNDPROC)ToolbarWndProc;
- wc.lpszClassName = c_szToolbarClass;
- wc.style = CS_DBLCLKS | CS_GLOBALCLASS;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = sizeof(PTBSTATE);
- wc.hInstance = hInstance; // use DLL instance if in DLL
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
- wc.lpszMenuName = NULL;
- if (!RegisterClass(&wc))
- return FALSE;
- }
- return TRUE;
- }
- #pragma code_seg()
- void PatB(HDC hdc,int x,int y,int dx,int dy, DWORD rgb)
- {
- RECT rc;
- SetBkColor(hdc,rgb);
- rc.left = x;
- rc.top = y;
- rc.right = x + dx;
- rc.bottom = y + dy;
- ExtTextOut(hdc,0,0,ETO_OPAQUE,&rc,NULL,0,NULL);
- }
- #ifndef UNICODE
- // Get actual number of characters that will be drawn into the given
- // rectangle by DrawTextEx. This is to avoid using DT_END_ELLIPSIS
- // on FarEast Win95 (golden) as it could sometimes put more characters
- // than what the rect actually could hold.
- UINT GetLengthDrawn(PTBSTATE ptb, HDC hdc, LPSTR psz, int cch, LPRECT lprc, UINT uiStyle)
- {
- DRAWTEXTPARAMS dtParams = {0};
- HDC hdcMem;
- HFONT hfontOld;
- ASSERT(psz);
- ASSERT(lprc);
- ASSERT(ptb);
- hdcMem = CreateCompatibleDC(hdc);
- hfontOld=SelectObject(hdcMem, ptb->hfontIcon);
- dtParams.cbSize = sizeof (dtParams);
- DrawTextEx(hdcMem, (LPSTR)psz, cch, lprc, uiStyle, &dtParams);
- SelectObject(hdcMem, hfontOld);
- DeleteDC(hdcMem);
- return dtParams.uiLengthDrawn;
- }
- #endif
- // Parameter fHighlight determines whether to draw text highlighted, for
- // new TBSTATE_MARKED
- //
- void DrawString(HDC hdc, int x, int y, int dx, int dy, PTSTR pszString,
- BOOL fHighlight, TBDRAWITEM * ptbdraw)
- {
- int oldMode;
- COLORREF oldBkColor;
- COLORREF oldTextColor;
- RECT rcText;
- UINT uiStyle = 0;
- PTBSTATE ptb;
- LPTBBUTTONDATA ptbb;
- ASSERT(ptbdraw);
- ptb = ptbdraw->ptb;
- ptbb = ptbdraw->pbutton;
- if (!(ptb->ci.style & TBSTYLE_LIST) && ((ptb->iDyBitmap + ptb->yPad + g_cyEdge) >= ptb->iButHeight))
- // there's no room to show the text -- bail out
- return;
- if (BTN_NO_SHOW_TEXT(ptb, ptbb))
- // don't show text for this button -- bail out
- return;
- if (fHighlight)
- {
- oldMode = SetBkMode (hdc, ptbdraw->tbcd.nHLStringBkMode);
- oldBkColor = SetBkColor (hdc, ptbdraw->tbcd.clrMark);
- oldTextColor = SetTextColor (hdc, ptbdraw->tbcd.clrTextHighlight);
- }
- else
- oldMode = SetBkMode(hdc, ptbdraw->tbcd.nStringBkMode);
- uiStyle = TBGetDrawTextFlags(ptb, DT_END_ELLIPSIS, ptbb);
- // If we're ex_vertical want to center the text
- if (!(ptb->dwStyleEx & TBSTYLE_EX_VERTICAL))
- {
- if (ptb->ci.style & TBSTYLE_LIST)
- {
- dy = max(ptb->dyIconFont, ptb->iDyBitmap);
- }
- else
- {
- if (!dy || ptb->dyIconFont < dy)
- dy = ptb->dyIconFont;
- }
- }
- SetRect( &rcText, x, y, x + dx, y + dy);
- #ifndef UNICODE
- if (g_fDBCSEnabled && !g_bRunOnMemphis
- && (ptbb->fsState & TBSTATE_ELLIPSES)
- && (ptb->nTextRows > 1))
- {
- LPSTR psz;
- UINT uiLengthDrawn;
- // FarEast Win95 has a bug that DT_END_ELLIPSIS can
- // miscalculate the number of characters that fit in
- // the specified rectangle. We have to avoid to use
- // DT_END_ELLIPSIS for the platform putting ellipsis
- // ourselves. Memphis will fix the bug so we won't do
- // this for them.
- //
- uiStyle &= ~DT_END_ELLIPSIS;
- psz = StrDup(pszString);
- if (psz)
- {
- uiLengthDrawn = GetLengthDrawn(ptb, hdc, psz, -1, &rcText, uiStyle);
- if (uiLengthDrawn > 3)
- {
- TruncateString(psz, uiLengthDrawn-2);
- lstrcat(psz, "...");
- }
- DrawText(hdc, (LPTSTR)psz, -1, &rcText, uiStyle);
- LocalFree(psz);
- }
- }
- else
- #endif
- DrawText(hdc, (LPTSTR)pszString, -1, &rcText, uiStyle);
- SetBkMode(hdc, oldMode);
- if (fHighlight)
- {
- SetBkColor (hdc, oldBkColor);
- SetTextColor (hdc, oldTextColor);
- }
- }
- LPTSTR TB_StrForButton(PTBSTATE ptb, LPTBBUTTONDATA pTBButton)
- {
- if (TBISSTRINGPTR(pTBButton->iString))
- return (LPTSTR)pTBButton->iString;
- else {
- if (pTBButton->iString != -1 &&
- pTBButton->iString < ptb->nStrings)
- return ptb->pStrings[pTBButton->iString];
- return NULL;
- }
- }
- HIMAGELIST TBGetImageList(PTBSTATE ptb, int iMode, int iIndex)
- {
- HIMAGELIST himl = NULL;
- ASSERT(iMode <= HIML_MAX);
- if (iIndex >= 0 && iIndex < ptb->cPimgs) {
- himl = ptb->pimgs[iIndex].himl[iMode];
- }
- return himl;
- }
- //
- // v5 toolbars support multiple imagelists. To use images from an alternate
- // imagelist, set the imagelist handle via TB_SETIMAGELIST(iIndex, himlAlt)
- // and set your button's iImage to MAKELONG(iImage, iIndex).
- //
- // APP COMPAT: GroupWise 5.5 passes crap as the iIndex (even though it
- // was documented as "must be zero"), so we enable this functionality
- // only for v5 toolbars. IE4 ignored the iIndex, which is why they got
- // away with it up until now.
- //
- #define MAX_TBIMAGELISTS 20 // arbitrary limit
- HIMAGELIST TBSetImageList(PTBSTATE ptb, int iMode, int iIndex, HIMAGELIST himl)
- {
- HIMAGELIST himlOld = NULL;
- // Watch out for app compat or for totally bogus parameters
- if (ptb->ci.iVersion < 5 || iIndex < 0 || iIndex >= MAX_TBIMAGELISTS)
- iIndex = 0;
- ASSERT(iMode <= HIML_MAX);
- if (iIndex >= ptb->cPimgs) {
- // asking for more than we have, realloc.
- void *p = CCLocalReAlloc(ptb->pimgs, (iIndex+1) * SIZEOF(TBIMAGELISTS));
- if (p) {
- ptb->pimgs = (TBIMAGELISTS*)p;
- ZeroMemory(&ptb->pimgs[ptb->cPimgs], (iIndex + 1 - ptb->cPimgs) * sizeof(TBIMAGELISTS));
- ptb->cPimgs = iIndex + 1; // iIndex is 0 based, but cPimgs is 1 based (it's a count, not an index)
- }
- }
- if (iIndex < ptb->cPimgs) {
- himlOld = ptb->pimgs[iIndex].himl[iMode];
- ptb->pimgs[iIndex].himl[iMode] = himl;
- }
- return himlOld;
- }
- // create a mono bitmap mask:
- // 1's where color == COLOR_BTNFACE || COLOR_3DHILIGHT
- // 0's everywhere else
- void CreateMask(int xoffset, int yoffset, int dx, int dy, BOOL fDrawGlyph, TBDRAWITEM * ptbdraw)
- {
- LPTSTR psz;
- IMAGELISTDRAWPARAMS imldp;
- HIMAGELIST himl;
- PTBSTATE ptb = ptbdraw->ptb;
- LPTBBUTTONDATA pTBButton = ptbdraw->pbutton;
- // initalize whole area with 1's
- PatBlt(ptb->hdcMono, 0, 0, dx, dy, WHITENESS);
- // create mask based on color bitmap
- // convert this to 1's
- himl = TBGetImageList(ptb, HIML_NORMAL, ptbdraw->iIndex);
- if (fDrawGlyph && himl)
- {
- imldp.cbSize = sizeof(imldp);
- imldp.himl = himl;
- imldp.i = ptbdraw->iImage;
- imldp.hdcDst = ptb->hdcMono;
- imldp.x = xoffset;
- imldp.y = yoffset;
- imldp.cx = 0;
- imldp.cy = 0;
- imldp.xBitmap= 0;
- imldp.yBitmap= 0;
- imldp.rgbBk = g_clrBtnFace;
- imldp.rgbFg = CLR_DEFAULT;
- imldp.fStyle = ILD_ROP | ILD_MASK;
- imldp.dwRop = SRCCOPY;
- ImageList_DrawIndirect(&imldp);
- imldp.fStyle = ILD_ROP | ILD_IMAGE;
- imldp.rgbBk = g_clrBtnHighlight;
- imldp.dwRop = SRCPAINT;
- ImageList_DrawIndirect(&imldp);
- }
- psz = TB_StrForButton(ptb, pTBButton);
- if (psz)
- {
- xoffset = 1;
- yoffset = 1;
- if (ptb->ci.style & TBSTYLE_LIST)
- {
- if (!(pTBButton->iBitmap == I_IMAGENONE &&
- (pTBButton->fsStyle & BTNS_AUTOSIZE)))
- {
- xoffset += ptb->iDxBitmap + ptb->iListGap;
- dx -= ptb->iDxBitmap + ptb->iListGap;
- }
- }
- else
- {
- yoffset += ptb->iDyBitmap + 1;
- dy -= ptb->iDyBitmap + 1;
- }
- if (!(ptb->dwStyleEx & TBSTYLE_EX_VERTICAL))
- {
- dx -= g_cxEdge;
- dy -= g_cyEdge;
- }
- // The FALSE in 4th param is so we don't get a box in the mask.
- DrawString(ptb->hdcMono, xoffset, yoffset, dx, dy, psz,
- FALSE, ptbdraw);
- }
- }
- void DrawBlankButton(HDC hdc, int x, int y, int dx, int dy, TBDRAWITEM * ptbdraw)
- {
- RECT r1;
- UINT state;
- // face color
- // The Office toolbar sends us bitmaps that are smaller than they claim they are
- // So we need to do the PatB or the window background shows through around the
- // edges of the button bitmap -jjk
- ASSERT(ptbdraw);
- state = ptbdraw->state;
- if (!(state & TBSTATE_CHECKED))
- PatB(hdc, x, y, dx, dy, ptbdraw->tbcd.clrBtnFace);
- if ( !(ptbdraw->dwCustom & TBCDRF_NOEDGES))
- {
- r1.left = x;
- r1.top = y;
- r1.right = x + dx;
- r1.bottom = y + dy;
- DrawEdge(hdc, &r1, (state & (TBSTATE_CHECKED | TBSTATE_PRESSED)) ? EDGE_SUNKEN : EDGE_RAISED, BF_RECT | BF_SOFT);
- }
- }
- // these are raster ops
- #define DSPDxax 0x00E20746 // BUGBUG: not used
- #define PSDPxax 0x00B8074A
- HWND g_hwndDebug = NULL;
- void DrawFace(HDC hdc, int x, int y, int offx, int offy, int dxText,
- int dyText, TBDRAWITEM * ptbdraw)
- {
- LPTSTR psz;
- IMAGELISTDRAWPARAMS imldp;
- BOOL fHotTrack = FALSE;
- UINT state;
- PTBSTATE ptb;
- LPTBBUTTONDATA ptButton;
- BOOL fImage; // !fImage means no image (as opposed to a blank image)
- ASSERT(ptbdraw);
- ptb = ptbdraw->ptb;
- ptButton = ptbdraw->pbutton;
- // AutosizeTextNoImage
- if ((ptb->ci.style & TBSTYLE_LIST) &&
- (ptbdraw->iImage == I_IMAGENONE) &&
- (ptButton->fsStyle & BTNS_AUTOSIZE)) {
- fImage = FALSE;
- } else {
- fImage = TRUE;
- }
- state = ptbdraw->state;
- if (state & TBSTATE_ENABLED)
- {
- fHotTrack = ptbdraw->fHotTrack;
- if (ptb->ci.style & TBSTYLE_FLAT)
- {
- UINT bdr = 0;
- if (state & (TBSTATE_PRESSED | TBSTATE_CHECKED))
- bdr = BDR_SUNKENOUTER;
- else if (fHotTrack)
- bdr = BDR_RAISEDINNER;
- if (bdr)
- {
- RECT rc;
- TB_GetItemRect(ptb, (UINT)(ptButton - ptb->Buttons), &rc);
- if (TB_HasSplitDDArrow(ptb, ptButton))
- rc.right -= ptb->dxDDArrowChar;
- if (!(ptbdraw->dwCustom & TBCDRF_NOEDGES) && ptb)
- CCDrawEdge(hdc, &rc, bdr, BF_RECT, &(ptb->clrsc));
- }
- }
- }
- imldp.himl = NULL;
- if (fHotTrack || (state & TBSTATE_CHECKED)) {
- imldp.himl = TBGetImageList(ptb, HIML_HOT, ptbdraw->iIndex);
- if (!imldp.himl)
- imldp.himl = TBGetImageList(ptb, HIML_NORMAL, ptbdraw->iIndex);
- } else if (DRAW_MONO_BTN(ptb, state) && (imldp.himl = TBGetImageList(ptb, HIML_DISABLED, ptbdraw->iIndex))) {
- // assigned in if statement
- } else if (imldp.himl = TBGetImageList(ptb, HIML_NORMAL, ptbdraw->iIndex)) {
- // assigned in if statement
- }
- if (imldp.himl && (ptbdraw->iImage != -1) && fImage)
- {
- COLORREF rgbBk = ptbdraw->tbcd.clrBtnFace;
- if (ptb->ci.style & TBSTYLE_TRANSPARENT)
- rgbBk = CLR_NONE;
- if (ptb->dwStyleEx & TBSTYLE_EX_INVERTIBLEIMAGELIST)
- rgbBk = CLR_DEFAULT;
- imldp.cbSize = sizeof(imldp);
- imldp.i = ptbdraw->iImage;
- imldp.hdcDst = hdc;
- imldp.x = x + offx;
- imldp.y = y + offy;
- imldp.cx = 0;
- imldp.cy = 0;
- imldp.xBitmap= 0;
- imldp.yBitmap= 0;
- imldp.rgbBk = rgbBk;
- imldp.rgbFg = CLR_DEFAULT;
- imldp.fStyle = ILD_NORMAL;
- if (state & (TBSTATE_CHECKED | TBSTATE_INDETERMINATE))
- imldp.fStyle = ILD_TRANSPARENT;
- #ifdef TBHIGHLIGHT_GLYPH
- if ((state & TBSTATE_MARKED) && !(ptbdraw->dwCustom & TBCDRF_NOMARK))
- imldp.fStyle = ILD_TRANSPARENT | ILD_BLEND50;
- #endif
- if (ptbdraw->dwCustom & TBCDRF_BLENDICON)
- imldp.fStyle = ILD_TRANSPARENT | ILD_BLEND50;
- ImageList_DrawIndirect(&imldp);
- #ifdef DEBUG
- if (g_hwndDebug == ptb->ci.hwnd) {
- imldp.hdcDst = GetDC(NULL);
- ImageList_DrawIndirect(&imldp);
- ReleaseDC(NULL, imldp.hdcDst);
- }
- #endif
- }
- psz = TB_StrForButton(ptb, ptButton);
- if (psz)
- {
- BOOL bHighlight = (state & TBSTATE_MARKED) && (ptb->ci.style & TBSTYLE_LIST) &&
- !(ptbdraw->dwCustom & TBCDRF_NOMARK);
- if ((state & (TBSTATE_PRESSED | TBSTATE_CHECKED)) &&
- !(ptbdraw->dwCustom & TBCDRF_NOOFFSET))
- {
- x++;
- if (ptb->ci.style & TBSTYLE_LIST)
- y++;
- }
- if (ptb->ci.style & TBSTYLE_LIST)
- {
- if (fImage)
- {
- x += ptb->iDxBitmap + ptb->iListGap;
- dxText -= ptb->iDxBitmap + ptb->iListGap;
- }
- else
- {
- // fudge for I_IMAGENONE buttons
- x += g_cxEdge;
- }
- }
- else
- {
- y += offy + ptb->iDyBitmap;
- dyText -= offy + ptb->iDyBitmap;
- }
- DrawString(hdc, x + 1, y + 1, dxText, dyText, psz, bHighlight, ptbdraw);
- }
- }
- void InitTBDrawItem(TBDRAWITEM * ptbdraw, PTBSTATE ptb, LPTBBUTTONDATA pbutton,
- UINT state, BOOL fHotTrack, int dxText, int dyText)
- {
- NMTBCUSTOMDRAW * ptbcd;
- NMCUSTOMDRAW * pnmcd;
- ASSERT(ptbdraw);
- ptbdraw->ptb = ptb;
- ptbdraw->pbutton = pbutton;
- ptbdraw->fHotTrack = fHotTrack;
- ptbdraw->iIndex = GET_HIML_INDEX(pbutton->DUMMYUNION_MEMBER(iBitmap));
- ptbdraw->iImage = GET_IMAGE_INDEX(pbutton->DUMMYUNION_MEMBER(iBitmap));
- ptbdraw->state = state;
- ptbcd = &ptbdraw->tbcd;
- ptbcd->hbrMonoDither = g_hbrMonoDither;
- ptbcd->hbrLines = GetStockObject(BLACK_BRUSH);
- ptbcd->hpenLines = GetStockObject(BLACK_PEN);
- ptbcd->clrMark = g_clrHighlight;
- ptbcd->clrBtnHighlight = g_clrBtnHighlight;
- ptbcd->clrTextHighlight = g_clrHighlightText;
- ptbcd->clrBtnFace = g_clrBtnFace;
- ptbcd->nStringBkMode = TRANSPARENT;
- ptbcd->nHLStringBkMode = OPAQUE;
- ptbcd->clrText = g_clrBtnText;
- SetRect(&ptbcd->rcText, 0, 0, dxText, dyText);
- pnmcd = (NMCUSTOMDRAW *)ptbcd;
- pnmcd->uItemState = CDISFromState(state);
- #ifdef KEYBOARDCUES
- #if 0
- // BUGBUG: Custom draw stuff for UISTATE (stephstm)
- if (CCGetUIState(&(ptb->ci), KC_TBD))
- pnmcd->uItemState |= CDIS_SHOWKEYBOARDCUES;
- #endif
- #endif
- if ((ptb->ci.style & TBSTYLE_FLAT) && fHotTrack)
- pnmcd->uItemState |= CDIS_HOT;
- }
- void DrawButton(HDC hdc, int x, int y, PTBSTATE ptb, LPTBBUTTONDATA ptButton, BOOL fActive)
- {
- // BUGBUG: cleanup -- separate layout calculation & rendering
- int yOffset;
- HBRUSH hbrOld;
- UINT state;
- int dxFace, dyFace;
- int dxText, dyText;
- int xCenterOffset;
- int dx = TBWidthOfButton(ptb, ptButton, hdc);
- HFONT oldhFont;
- int dy = ptb->iButHeight;
- TBDRAWITEM tbdraw = { 0 };
- NMTBCUSTOMDRAW * ptbcd = &tbdraw.tbcd;
- NMCUSTOMDRAW * pnmcd = (NMCUSTOMDRAW *)ptbcd;
- COLORREF clrSave;
- BOOL fHotTrack;
- HFONT hFontNoAntiAlias = NULL;
- state = (UINT)ptButton->fsState;
- // make local copy of state and do proper overriding
- if (state & TBSTATE_INDETERMINATE) {
- if (state & TBSTATE_PRESSED)
- state &= ~TBSTATE_INDETERMINATE;
- else if (state & TBSTATE_ENABLED)
- state = TBSTATE_INDETERMINATE;
- else
- state &= ~TBSTATE_INDETERMINATE;
- }
- if (!fActive) {
- state &= ~TBSTATE_ENABLED;
- }
- fHotTrack = TBIsHotTrack(ptb, ptButton, state);
- pnmcd->hdc = hdc;
- pnmcd->dwItemSpec = ptButton->idCommand;
- pnmcd->uItemState = 0;
- pnmcd->lItemlParam = (LPARAM)ptButton->dwData;
- SetRect(&pnmcd->rc, x, y, x + dx, y + dy);
- dxText = dx - (3 * g_cxEdge);
- if (ptb->dwStyleEx & TBSTYLE_EX_VERTICAL)
- {
- dyText = dy;
- }
- else
- {
- dyText = dy - (2 * g_cyEdge);
- }
- InitTBDrawItem(&tbdraw, ptb, ptButton, state, fHotTrack, dxText, dyText);
- tbdraw.dwCustom = CICustomDrawNotify(&ptb->ci, CDDS_ITEMPREPAINT, (NMCUSTOMDRAW *)ptbcd);
- // We gotta update our concept of hotness
- tbdraw.fHotTrack = fHotTrack = pnmcd->uItemState & CDIS_HOT;
- if (!(tbdraw.dwCustom & CDRF_SKIPDEFAULT ))
- {
- // Get the state back from what custom draw may have set
- state = tbdraw.state = StateFromCDIS(pnmcd->uItemState);
- dxFace = dx - (2 * g_cxEdge);
- dyFace = dy - (2 * g_cyEdge);
- dxText = ptbcd->rcText.right - ptbcd->rcText.left;
- dyText = ptbcd->rcText.bottom - ptbcd->rcText.top;
- if (TB_HasDDArrow(ptb, ptButton) && !TB_HasTopDDArrow(ptb, ptButton)) {
- int iAdjust = TBDDArrowAdjustment(ptb, ptButton);
- dxFace -= iAdjust;
- dxText -= iAdjust;
- }
- // Should we display the font using the GDI AntiAliasing?
- if (!ptb->fAntiAlias)
- {
- // No. Must be doing drag and drop. We don't want to AntiAlias because the
- // Purple color key will show through and it looks ugly.
- LOGFONT lfFont;
- if (GetObject(ptb->hfontIcon, sizeof(lfFont), &lfFont))
- {
- lfFont.lfQuality = NONANTIALIASED_QUALITY;
- hFontNoAntiAlias = CreateFontIndirect(&lfFont);
- }
- }
- if (hFontNoAntiAlias)
- oldhFont = SelectObject(hdc, hFontNoAntiAlias);
- else
- oldhFont = SelectObject(hdc, ptb->hfontIcon);
- clrSave = SetTextColor(hdc, ptbcd->clrText);
- if (!(ptb->ci.style & TBSTYLE_FLAT))
- DrawBlankButton(hdc, x, y, dx, dy, &tbdraw);
- // move coordinates inside border and away from upper left highlight.
- // the extents change accordingly.
- x += g_cxEdge;
- y += g_cyEdge;
- if (ptb->dwStyleEx & TBSTYLE_EX_VERTICAL)
- {
- yOffset = (ptb->iButHeight - ptb->iDyBitmap) / 2;
- }
- else
- {
- // calculate offset of face from (x,y). y is always from the top,
- // so the offset is easy. x needs to be centered in face.
- // center it taking the padding into account the padding area
- yOffset = (ptb->yPad - (2 * g_cyEdge)) / 2;
- }
- if (yOffset < 0)
- yOffset = 0;
- if ((ptb->ci.style & TBSTYLE_LIST) && !BTN_NO_SHOW_TEXT(ptb, ptButton)) {
- xCenterOffset = ptb->xPad / 2;
- } else if (TB_HasTopDDArrow(ptb, ptButton)) {
- //
- // Layout of "top dropdown" buttons looks like this:
- //
- // icon
- // fudge | dropdown arrow
- // | | |
- // v v v
- // +-+-+-------+--+-+
- // | | | | | |
- // | | | | | |
- // +-+-+-------+--+-+
- // | <text> |
- // +----------------+
- //
- // |<--- dxFace --->|
- //
- // xCenterOffset is the offset at which to start drawing the icon.
- //
- xCenterOffset = (dxFace + CX_TOP_FUDGE - (ptb->iDxBitmap + ptb->dxDDArrowChar)) / 2;
- } else {
- xCenterOffset = (dxFace - ptb->iDxBitmap) / 2;
- }
- if (state & (TBSTATE_PRESSED | TBSTATE_CHECKED) &&
- !(tbdraw.dwCustom & TBCDRF_NOOFFSET))
- {
- // pressed state moves down and to the right
- xCenterOffset++;
- yOffset++;
- }
- // draw the dithered background
- if ((!fHotTrack || ptb->ci.iVersion < 5) &&
- (((state & (TBSTATE_CHECKED | TBSTATE_INDETERMINATE)) ||
- ((state & TBSTATE_MARKED) &&
- !(ptb->ci.style & TBSTYLE_FLAT) &&
- !(tbdraw.dwCustom & TBCDRF_NOMARK)))))
- {
- //Custom Draw can set hbrMonoDither to be NULL. Validate it before using it
- hbrOld = ptbcd->hbrMonoDither ? SelectObject(hdc, ptbcd->hbrMonoDither) : NULL;
- if (hbrOld)
- {
- COLORREF clrText, clrBack;
- #ifdef TBHIGHLIGHT_BACK
- if (state & TBSTATE_MARKED)
- clrText = SetTextColor(hdc, ptbcd->clrMark);
- else
- #endif
- clrText = SetTextColor(hdc, ptbcd->clrBtnHighlight); // 0 -> 0
- clrBack = SetBkColor(hdc, ptbcd->clrBtnFace); // 1 -> 1
- // only draw the dither brush where the mask is 1's
- PatBlt(hdc, x, y, dxFace, dyFace, PATCOPY);
- SelectObject(hdc, hbrOld);
- SetTextColor(hdc, clrText);
- SetBkColor(hdc, clrBack);
- }
- }
- // Paint the background of the hot-tracked item if the
- // custom draw said so
- if ((tbdraw.dwCustom & TBCDRF_HILITEHOTTRACK) && fHotTrack)
- {
- PatB(hdc, pnmcd->rc.left, pnmcd->rc.top,
- pnmcd->rc.right - pnmcd->rc.left, pnmcd->rc.bottom - pnmcd->rc.top,
- ptbcd->clrHighlightHotTrack);
- }
- tbdraw.iImage = ptButton->DUMMYUNION_MEMBER(iBitmap);
- if((ptButton->DUMMYUNION_MEMBER(iBitmap) == I_IMAGECALLBACK) && ptb->fHimlNative)
- {
- NMTBDISPINFO tbgdi = {0};
- tbgdi.dwMask = TBNF_IMAGE;
- TBGetItem(ptb,ptButton,&tbgdi);
- tbdraw.iImage = tbgdi.iImage;
- }
- tbdraw.iIndex = GET_HIML_INDEX(tbdraw.iImage);
- tbdraw.iImage = GET_IMAGE_INDEX(tbdraw.iImage);
- // Now put on the face.
- // TODO: Validate himlDisabled and ensure that the index is in range
- if (!DRAW_MONO_BTN(ptb, state) ||
- TBGetImageList(ptb, HIML_DISABLED, tbdraw.iIndex))
- {
- // regular version
- int yStart = y;
- if (ptb->dwStyleEx & TBSTYLE_EX_VERTICAL)
- yStart -= g_cyEdge;
- DrawFace(hdc, x, yStart, xCenterOffset, yOffset, dxText, dyText, &tbdraw);
- }
- if (DRAW_MONO_BTN(ptb, state))
- {
- HBITMAP hbmOld;
- //initialize the monochrome dc
- if (!ptb->hdcMono) {
- ptb->hdcMono = CreateCompatibleDC(hdc);
- if (!ptb->hdcMono)
- return;
- SetTextColor(ptb->hdcMono, 0L);
- SelectObject(ptb->hdcMono, ptb->hfontIcon);
- }
- hbmOld = SelectObject(ptb->hdcMono, ptb->hbmMono);
- //
- // If we a mirrored DC, mirror the Memory DC so that
- // text written on the bitmap won't get flipped.
- //
- if ((IS_DC_RTL_MIRRORED(hdc)) &&
- (!(IS_DC_RTL_MIRRORED(ptb->hdcMono))))
- {
- SET_DC_RTL_MIRRORED(ptb->hdcMono);
- }
- // disabled version (or indeterminate)
- CreateMask(xCenterOffset, yOffset, dxFace, dyFace, (TBGetImageList(ptb, HIML_DISABLED, tbdraw.iIndex) == NULL), &tbdraw);
- SetTextColor(hdc, 0L); // 0's in mono -> 0 (for ROP)
- SetBkColor(hdc, 0x00FFFFFF); // 1's in mono -> 1
- // draw glyph's etched-effect
- if (!(state & TBSTATE_INDETERMINATE) &&
- !(tbdraw.dwCustom & TBCDRF_NOETCHEDEFFECT)) {
- hbrOld = SelectObject(hdc, g_hbrBtnHighlight);
- if (hbrOld) {
- // draw hilight color where we have 0's in the mask
- BitBlt(hdc, x + 1, y + 1, dxFace, dyFace, ptb->hdcMono, 0, 0, PSDPxax);
- SelectObject(hdc, hbrOld);
- }
- }
- // gray out glyph
- hbrOld = SelectObject(hdc, g_hbrBtnShadow);
- if (hbrOld) {
- // draw the shadow color where we have 0's in the mask
- BitBlt(hdc, x, y, dxFace, dyFace, ptb->hdcMono, 0, 0, PSDPxax);
- SelectObject(hdc, hbrOld);
- }
- if (state & TBSTATE_CHECKED) {
- BitBlt(ptb->hdcMono, 1, 1, dxFace - 1, dyFace - 1, ptb->hdcMono, 0, 0, SRCAND);
- }
- SelectObject(ptb->hdcMono, hbmOld);
- }
- if (TB_HasDDArrow(ptb, ptButton))
- {
- WORD wDSAFlags = DCHF_TRANSPARENT | DCHF_FLIPPED;
- BOOL fPressedDD = ((ptb->Buttons + ptb->iPressedDD) == ptButton);
- RECT rc;
- if (TB_HasTopDDArrow(ptb, ptButton)) {
- // position the dd arrow up next to the bitmap
- rc.left = x + xCenterOffset + ptb->iDxBitmap;
- rc.right = rc.left + ptb->dxDDArrowChar;
- rc.top = y + yOffset;
- rc.bottom = rc.top + ptb->iDyBitmap;
- }
- else
- {
- // position the dd arrow to the right of the text & bitmap
- TB_GetItemRect(ptb, (UINT)(ptButton - ptb->Buttons), &rc);
- rc.left = rc.right - ptb->dxDDArrowChar;
- }
- if (TB_HasUnsplitDDArrow(ptb, ptButton)) {
- // if a non-split dd arrow, don't draw a border.
- wDSAFlags |= DCHF_NOBORDER;
- }
- if (DRAW_MONO_BTN(ptb, state)) {
- // DFCS_INACTIVE means "draw the arrow part grayed"
- wDSAFlags |= DCHF_INACTIVE;
- }
- // if TB_HasTopDDArrow, we've already offset rect, so don't draw DCHF_PUSHED
- else if ((fPressedDD || (state & (TBSTATE_CHECKED | TBSTATE_PRESSED))) &&
- !TB_HasTopDDArrow(ptb, ptButton)) {
- // DCHF_PUSHED means "offset the arrow and draw indented border"
- wDSAFlags |= DCHF_PUSHED;
- }
- else if (fHotTrack || !(ptb->ci.style & TBSTYLE_FLAT)) {
- // DCHF_HOT means "draw raised border"
- // non-flat dropdown arrows are either pushed or hot
- wDSAFlags |= DCHF_HOT;
- }
- DrawScrollArrow(hdc, &rc, wDSAFlags);
- }
- SelectObject(hdc, oldhFont);
- SetTextColor(hdc, clrSave);
- if (hFontNoAntiAlias)
- {
- DeleteObject(hFontNoAntiAlias);
- }
- }
- if (tbdraw.dwCustom & CDRF_NOTIFYPOSTPAINT)
- CICustomDrawNotify(&ptb->ci, CDDS_ITEMPOSTPAINT, (NMCUSTOMDRAW *)ptbcd);
- }
- // make sure that g_hbmMono is big enough to do masks for this
- // size of button. if not, fail.
- BOOL CheckMonoMask(PTBSTATE ptb, int width, int height)
- {
- BITMAP bm;
- HBITMAP hbmTemp;
- if (ptb->hbmMono) {
- GetObject(ptb->hbmMono, sizeof(BITMAP), &bm);
- if (width <= bm.bmWidth && height <= bm.bmHeight) {
- return TRUE;
- }
- }
- // Add a bit of fudge to keep this from being reallocated too often.
- hbmTemp = CreateMonoBitmap(width+8, height+8);
- if (!hbmTemp)
- return FALSE;
- if (ptb->hbmMono)
- DeleteObject(ptb->hbmMono);
- ptb->hbmMono = hbmTemp;
- return TRUE;
- }
- /*
- ** GrowToolbar
- **
- ** Attempt to grow the button size.
- **
- ** The calling function can either specify a new internal measurement
- ** (GT_INSIDE) or a new external measurement.
- **
- ** GT_MASKONLY updates the mono mask and nothing else.
- */
- BOOL GrowToolbar(PTBSTATE ptb, int newButWidth, int newButHeight, UINT flags)
- {
- if (!newButWidth)
- newButWidth = DEFAULTBUTTONX;
- if (!newButHeight)
- newButHeight = DEFAULTBUTTONY;
- // if growing based on inside measurement, get full size
- if (flags & GT_INSIDE)
- {
- if (ptb->ci.style & TBSTYLE_LIST)
- newButWidth += ptb->iDxBitmap + ptb->iListGap;
- newButHeight += ptb->yPad;
- newButWidth += ptb->xPad;
- // if toolbar already has strings, don't shrink width it because it
- // might clip room for the string
- if ((newButWidth < ptb->iButWidth) && ptb->nStrings &&
- (ptb->ci.iVersion < 5 || ptb->nTextRows > 0))
- newButWidth = ptb->iButWidth;
- }
- else {
- if (newButHeight == -1)
- newButHeight = ptb->iButHeight;
- if (newButWidth == -1)
- newButWidth = ptb->iButWidth;
- if (newButHeight < ptb->iDyBitmap + ptb->yPad)
- newButHeight = ptb->iDyBitmap + ptb->yPad;
- if (newButWidth < ptb->iDxBitmap + ptb->xPad)
- newButWidth = ptb->iDxBitmap + ptb->xPad;
- }
- // if the size of the toolbar is actually growing, see if shadow
- // bitmaps can be made sufficiently large.
- if (!ptb->hbmMono || (newButWidth > ptb->iButWidth) || (newButHeight > ptb->iButHeight)) {
- if (!CheckMonoMask(ptb, newButWidth, newButHeight))
- return(FALSE);
- }
- if (flags & GT_MASKONLY)
- return(TRUE);
- if (!(flags & GT_INSIDE) && ((ptb->iButWidth != newButWidth) || (ptb->iButHeight != newButHeight)))
- InvalidateRect(ptb->ci.hwnd, NULL, TRUE);
- ptb->iButWidth = newButWidth;
- ptb->iButHeight = newButHeight;
- // bar height has 2 pixels above, 2 below
- if (ptb->ci.style & TBSTYLE_FLAT)
- ptb->iYPos = 0;
- else
- ptb->iYPos = 2;
- TBInvalidateItemRects(ptb);
- return TRUE;
- }
- BOOL SetBitmapSize(PTBSTATE ptb, int width, int height)
- {
- int realh;
- if (!width)
- width = 1;
- if (!height)
- height = 1;
- if (width == -1)
- width = ptb->iDxBitmap;
- if (height == -1)
- height = ptb->iDyBitmap;
- realh = height;
- if ((ptb->iDxBitmap == width) && (ptb->iDyBitmap == height))
- return TRUE;
- if (TBHasStrings(ptb))
- realh = HeightWithString(ptb, height);
- if (GrowToolbar(ptb, width, realh, GT_INSIDE)) {
- ptb->iDxBitmap = width;
- ptb->iDyBitmap = height;
- // the size changed, we need to rebuild the imagelist
- InvalidateRect(ptb->ci.hwnd, NULL, TRUE);
- TBInvalidateImageList(ptb);
- return TRUE;
- }
- return FALSE;
- }
- void TB_OnSysColorChange(PTBSTATE ptb)
- {
- int i;
- InitGlobalColors();
- // Reset all of the bitmaps
- for (i = 0; i < ptb->cPimgs; i++) {
- HIMAGELIST himl = TBGetImageList(ptb, HIML_NORMAL, i);
- if (himl)
- ImageList_SetBkColor(himl, (ptb->ci.style & TBSTYLE_TRANSPARENT) ? CLR_NONE : g_clrBtnFace);
- himl = TBGetImageList(ptb, HIML_HOT, i);
- if (himl)
- ImageList_SetBkColor(himl, (ptb->ci.style & TBSTYLE_TRANSPARENT) ? CLR_NONE : g_clrBtnFace);
- }
- }
- #define CACHE 0x01
- #define BUILD 0x02
- void PASCAL ReleaseMonoDC(PTBSTATE ptb)
- {
- if (ptb->hdcMono) {
- SelectObject(ptb->hdcMono, g_hfontSystem);
- DeleteDC(ptb->hdcMono);
- ptb->hdcMono = NULL;
- }
- }
- void TB_OnEraseBkgnd(PTBSTATE ptb, HDC hdc)
- {
- NMTBCUSTOMDRAW tbcd = { 0 };
- DWORD dwRes = FALSE;
- tbcd.nmcd.hdc = hdc;
- if (ptb->ci.style & TBSTYLE_CUSTOMERASE) {
- ptb->ci.dwCustom = CICustomDrawNotify(&ptb->ci, CDDS_PREERASE, (NMCUSTOMDRAW *)&tbcd);
- } else {
- ptb->ci.dwCustom = CDRF_DODEFAULT;
- }
- if (!(ptb->ci.dwCustom & CDRF_SKIPDEFAULT))
- {
- // for transparent toolbars, forward erase background to parent
- // but handle thru DefWindowProc in the event parent doesn't paint
- if (!(ptb->ci.style & TBSTYLE_TRANSPARENT) ||
- !CCForwardEraseBackground(ptb->ci.hwnd, hdc))
- DefWindowProc(ptb->ci.hwnd, WM_ERASEBKGND, (WPARAM) hdc, 0);
- }
- if (ptb->ci.dwCustom & CDRF_NOTIFYPOSTERASE)
- CICustomDrawNotify(&ptb->ci, CDDS_POSTERASE, (NMCUSTOMDRAW *)&tbcd);
- }
- void PASCAL DrawInsertMark(HDC hdc, LPRECT prc, BOOL fHorizMode, COLORREF clr)
- {
- HPEN hPnMark = CreatePen(PS_SOLID, 1, clr);
- HPEN hOldPn;
- POINT rgPoint[4];
- if (!hPnMark)
- hPnMark = (HPEN)GetStockObject(BLACK_PEN); // fallback to draw with black pen
- hOldPn = (HPEN)SelectObject(hdc, (HGDIOBJ)hPnMark);
- if ( fHorizMode )
- {
- int iXCentre = (prc->left + prc->right) /2;
- rgPoint[0].x = iXCentre + 1;
- rgPoint[0].y = prc->top + 2;
- rgPoint[1].x = iXCentre + 3;
- rgPoint[1].y = prc->top;
- rgPoint[2].x = iXCentre - 2;
- rgPoint[2].y = prc->top;
- rgPoint[3].x = iXCentre;
- rgPoint[3].y = prc->top + 2;
- // draw the top bit...
- Polyline( hdc, rgPoint, 4 );
- rgPoint[0].x = iXCentre;
- rgPoint[0].y = prc->top;
- rgPoint[1].x = iXCentre;
- rgPoint[1].y = prc->bottom - 1;
- rgPoint[2].x = iXCentre + 1;
- rgPoint[2].y = prc->bottom - 1;
- rgPoint[3].x = iXCentre + 1;
- rgPoint[3].y = prc->top;
- // draw the middle...
- Polyline( hdc, rgPoint, 4 );
- rgPoint[0].x = iXCentre + 1;
- rgPoint[0].y = prc->bottom - 3;
- rgPoint[1].x = iXCentre + 3;
- rgPoint[1].y = prc->bottom - 1;
- rgPoint[2].x = iXCentre - 2;
- rgPoint[2].y = prc->bottom - 1;
- rgPoint[3].x = iXCentre;
- rgPoint[3].y = prc->bottom - 3;
- // draw the bottom bit...
- Polyline( hdc, rgPoint, 4 );
- }
- else
- {
- int iYCentre = (prc->top + prc->bottom) /2;
- rgPoint[0].x = prc->left + 2;
- rgPoint[0].y = iYCentre;
- rgPoint[1].x = prc->left;
- rgPoint[1].y = iYCentre - 2;
- rgPoint[2].x = prc->left;
- rgPoint[2].y = iYCentre + 3;
- rgPoint[3].x = prc->left + 2;
- rgPoint[3].y = iYCentre + 1;
- // draw the top bit...
- Polyline( hdc, rgPoint, 4 );
- rgPoint[0].x = prc->left;
- rgPoint[0].y = iYCentre;
- rgPoint[1].x = prc->right - 1;
- rgPoint[1].y = iYCentre;
- rgPoint[2].x = prc->right - 1;
- rgPoint[2].y = iYCentre + 1;
- rgPoint[3].x = prc->left;
- rgPoint[3].y = iYCentre + 1;
- // draw the middle...
- Polyline( hdc, rgPoint, 4 );
- rgPoint[0].x = prc->right - 3;
- rgPoint[0].y = iYCentre;
- rgPoint[1].x = prc->right - 1;
- rgPoint[1].y = iYCentre - 2;
- rgPoint[2].x = prc->right - 1;
- rgPoint[2].y = iYCentre + 3;
- rgPoint[3].x = prc->right - 3;
- rgPoint[3].y = iYCentre + 1;
- // draw the bottom bit...
- Polyline( hdc, rgPoint, 4 );
- }
- SelectObject( hdc, hOldPn );
- DeleteObject((HGDIOBJ)hPnMark);
- }
- BOOL TBIsRectClipped(PTBSTATE ptb, LPRECT prc)
- {
- RECT rc;
- RECT rcTB;
- if (ptb->dwStyleEx & TBSTYLE_EX_MULTICOLUMN)
- CopyRect(&rcTB, &ptb->rc);
- else
- GetClientRect(ptb->ci.hwnd, &rcTB);
- if (IntersectRect(&rc, &rcTB, prc)) {
- if (EqualRect(prc, &rc))
- return FALSE;
- }
- return TRUE;
- }
- BOOL TBShouldDrawButton(PTBSTATE ptb, LPRECT prcBtn, HDC hdc)
- {
- // don't bother drawing buttons that aren't in the dc clipping region
- if (RectVisible(hdc, prcBtn)) {
- if (ptb->dwStyleEx & TBSTYLE_EX_HIDECLIPPEDBUTTONS)
- return !TBIsRectClipped(ptb, prcBtn);
- else
- return TRUE;
- }
- return FALSE;
- }
- // goin horizontal . . .
- void DrawToolbarH(PTBSTATE ptb, HDC hdc, LPRECT prc)
- {
- int iButton, xButton, yButton, cxBar;
- LPTBBUTTONDATA pAllButtons = ptb->Buttons;
- cxBar = prc->right - prc->left;
- yButton = ptb->iYPos;
- prc->top = ptb->iYPos;
- prc->bottom = ptb->iYPos + ptb->iButHeight; // BUGBUG (scotth): what if first btn is a separator?
- for (iButton = 0, xButton = ptb->xFirstButton;
- iButton < ptb->iNumButtons; iButton++)
- {
- LPTBBUTTONDATA pButton = &pAllButtons[iButton];
- if (!(pButton->fsState & TBSTATE_HIDDEN))
- {
- int cxButton = TBWidthOfButton(ptb, pButton, hdc);
- // Is there anything to draw?
- if (!(pButton->fsStyle & BTNS_SEP) || (ptb->ci.style & TBSTYLE_FLAT))
- {
- // Yes
- prc->left = xButton;
- prc->right = xButton + cxButton;
- if (TBShouldDrawButton(ptb, prc, hdc))
- {
- // Draw separator?
- if (pButton->fsStyle & BTNS_SEP)
- {
- // Yes; must be a flat separator. Is this toolbar vertical?
- if (ptb->ci.style & CCS_VERT)
- {
- // Yes; draw a horizontal separator. Center w/in the
- // button rect
- int iSave = prc->top;
- prc->top += (TBGetSepHeight(ptb, pButton) - 1) / 2;
- InflateRect(prc, -g_cxEdge, 0);
- CCDrawEdge(hdc, prc, EDGE_ETCHED, BF_TOP, &(ptb->clrsc));
- InflateRect(prc, g_cxEdge, 0);
- prc->top = iSave;
- }
- else
- {
- // No; draw a vertical separator
- prc->left += (cxButton - 1) / 2;
- InflateRect(prc, 0, -g_cyEdge);
- CCDrawEdge(hdc, prc, EDGE_ETCHED, BF_LEFT, &(ptb->clrsc));
- InflateRect(prc, 0, g_cyEdge);
- }
- }
- else
- {
- // No
- DrawButton(hdc, xButton, yButton, ptb, pButton, ptb->fActive);
- }
- }
- }
- xButton += (cxButton - s_dxOverlap);
- if (pButton->fsState & TBSTATE_WRAP)
- {
- int dy;
- if (pButton->fsStyle & BTNS_SEP)
- {
- if (ptb->ci.style & CCS_VERT)
- dy = TBGetSepHeight(ptb, pButton);
- else
- {
- if (ptb->ci.style & TBSTYLE_FLAT)
- {
- // Draw a separator across the entire toolbar to separate rows.
- // For horizontal toolbars only.
- RECT rcMid;
- rcMid.top = prc->top + ptb->iButHeight + ((TBGetSepHeight(ptb, pButton) - 1) / 2);
- rcMid.bottom = rcMid.top + g_cxEdge;
- rcMid.left = g_cxEdge;
- rcMid.right = cxBar - g_cxEdge;
- CCDrawEdge(hdc, &rcMid, EDGE_ETCHED, BF_TOP, &(ptb->clrsc));
- }
- dy = ptb->iButHeight + TBGetSepHeight(ptb, pButton);
- }
- }
- else
- dy = ptb->iButHeight;
- xButton = ptb->xFirstButton;
- yButton += dy;
- prc->top += dy;
- prc->bottom += dy;
- }
- }
- }
- }
- // goin vertical . . .
- void DrawToolbarV(PTBSTATE ptb, HDC hdc, LPRECT prc)
- {
- int iButton, xButton, yButton, cyBar;
- LPTBBUTTONDATA pAllButtons = ptb->Buttons;
- NMTBCUSTOMDRAW tbcd = { 0 };
- LPTBBUTTONDATA pButton = pAllButtons;
- cyBar = prc->bottom - prc->top;
- xButton = ptb->xFirstButton;
- prc->left = xButton;
- prc->right = prc->left + ptb->iButWidth;
- for (iButton = 0, yButton = 0;
- iButton < ptb->iNumButtons; iButton++, pButton++)
- {
- if (!(pButton->fsState & TBSTATE_HIDDEN))
- {
- // Is there anything to draw?
- if (!(pButton->fsStyle & BTNS_SEP) || (ptb->ci.style & TBSTYLE_FLAT))
- {
- int cyButton;
- if (pButton->fsStyle & BTNS_SEP)
- cyButton = TBGetSepHeight(ptb, pButton);
- else
- cyButton = ptb->iButHeight;
- prc->top = yButton;
- prc->bottom = yButton + cyButton;
- if (TBShouldDrawButton(ptb, prc, hdc))
- {
- // Draw separator?
- if (pButton->fsStyle & BTNS_SEP)
- {
- DWORD dwCustRet;
- NMTBCUSTOMDRAW tbcd = { 0 };
- tbcd.nmcd.hdc = hdc;
- tbcd.nmcd.dwItemSpec = -1;
- CopyRect(&tbcd.nmcd.rc, prc);
- dwCustRet = CICustomDrawNotify(&ptb->ci, CDDS_ITEMPREPAINT, (NMCUSTOMDRAW *)&tbcd);
- if ( !(CDRF_SKIPDEFAULT & dwCustRet) )
- {
- // Yes; must be a flat separator.
- InflateRect(prc, -g_cxEdge, 0);
- CCDrawEdge(hdc, prc, EDGE_ETCHED, BF_TOP, &(ptb->clrsc));
- InflateRect(prc, g_cxEdge, 0);
- }
- }
- else
- {
- // No
- DrawButton(hdc, xButton, yButton, ptb, pButton, ptb->fActive);
- }
- }
- yButton += cyButton;
- }
- if (pButton->fsState & TBSTATE_WRAP)
- {
- int dx;
- if (ptb->ci.style & TBSTYLE_FLAT)
- {
- // Draw a separator vertival across the entire toolbar to separate cols.
- // For vertical toolbars only.
- RECT rcMid;
- rcMid.top = ptb->rc.top + g_cxEdge;
- rcMid.bottom = ptb->rc.bottom - g_cxEdge;
- rcMid.left = xButton + ptb->iButWidth;
- rcMid.right = rcMid.left + g_cxEdge;
- CCDrawEdge(hdc, &rcMid, EDGE_ETCHED, BF_LEFT, &(ptb->clrsc));
- }
- dx = ptb->iButWidth + g_cxEdge;
- yButton = 0;
- xButton += dx;
- prc->left += dx;
- prc->right += dx;
- }
- }
- }
- }
- COLORREF TB_GetInsertMarkColor(PTBSTATE ptb)
- {
- if (ptb->clrim == CLR_DEFAULT)
- return g_clrBtnText;
- else
- return ptb->clrim;
- }
- void TBPaint(PTBSTATE ptb, HDC hdcIn)
- {
- RECT rc;
- HDC hdc;
- PAINTSTRUCT ps;
- NMTBCUSTOMDRAW tbcd = { 0 };
- GetClientRect(ptb->ci.hwnd, &rc);
- if (hdcIn)
- {
- hdc = hdcIn;
- }
- else
- hdc = BeginPaint(ptb->ci.hwnd, &ps);
- if (!rc.right)
- goto Error1;
- tbcd.nmcd.hdc = hdc;
- tbcd.nmcd.rc = rc;
- ptb->ci.dwCustom = CICustomDrawNotify(&ptb->ci, CDDS_PREPAINT, (NMCUSTOMDRAW *)&tbcd);
- if (!(ptb->ci.dwCustom & CDRF_SKIPDEFAULT))
- {
- if (!ptb->fHimlValid)
- TBBuildImageList(ptb);
- if (ptb->dwStyleEx & TBSTYLE_EX_VERTICAL)
- DrawToolbarV(ptb, hdc, &rc);
- else
- DrawToolbarH(ptb, hdc, &rc);
- if (ptb->iInsert!=-1)
- {
- BOOL fHorizMode = !(ptb->ci.style & CCS_VERT);
- RECT rc;
- if (GetInsertMarkRect(ptb, &rc, fHorizMode))
- {
- DrawInsertMark(hdc, &rc, fHorizMode, TB_GetInsertMarkColor(ptb));
- }
- }
- ReleaseMonoDC(ptb);
- }
- if (ptb->ci.dwCustom & CDRF_NOTIFYPOSTPAINT)
- {
- tbcd.nmcd.hdc = hdc;
- tbcd.nmcd.uItemState = 0;
- tbcd.nmcd.lItemlParam = 0;
- CICustomDrawNotify(&ptb->ci, CDDS_POSTPAINT, (NMCUSTOMDRAW *)&tbcd);
- }
- Error1:
- if (hdcIn == NULL)
- EndPaint(ptb->ci.hwnd, &ps);
- }
- void TB_GetItemDropDownRect(PTBSTATE ptb, UINT uButton, LPRECT lpRect)
- {
- TB_GetItemRect(ptb,uButton,lpRect);
- lpRect->left = lpRect->right - ptb->dxDDArrowChar;
- }
- int TBHeightOfButton(PTBSTATE ptb, LPTBBUTTONDATA ptbb)
- {
- int dy;
- if ((ptbb->fsStyle & BTNS_SEP) &&
- (ptbb->fsState & TBSTATE_WRAP || ptb->dwStyleEx & TBSTYLE_EX_VERTICAL))
- {
- if (!(ptb->ci.style & CCS_VERT) && !(ptb->dwStyleEx & TBSTYLE_EX_VERTICAL))
- {
- dy = TBGetSepHeight(ptb, ptbb) + ptb->iButHeight;
- }
- else
- {
- dy = TBGetSepHeight(ptb, ptbb);
- }
- }
- else
- {
- dy = ptb->iButHeight;
- }
- return dy;
- }
- void TB_CalcItemRects(PTBSTATE ptb)
- {
- int iButton, xPos, yPos;
- ASSERT(!ptb->fItemRectsValid);
- xPos = ptb->xFirstButton;
- yPos = ptb->iYPos;
- for (iButton = 0; iButton < ptb->iNumButtons; iButton++)
- {
- int xPosButton;
- LPTBBUTTONDATA pButton = &ptb->Buttons[iButton];
- if (!(pButton->fsState & TBSTATE_HIDDEN))
- {
- if ((pButton->fsState & TBSTATE_WRAP) && (pButton->fsStyle & BTNS_SEP))
- xPosButton = ptb->xFirstButton;
- else
- xPosButton = xPos;
- pButton->pt.x = xPosButton;
- pButton->pt.y = yPos;
- if (ptb->dwStyleEx & TBSTYLE_EX_VERTICAL)
- {
- if (pButton->fsState & TBSTATE_WRAP)
- {
- xPos += (ptb->iButWidth + g_cxEdge); // to not overwrite the edge.
- yPos = 0;
- }
- else if (pButton->fsStyle & BTNS_SEP)
- yPos += (TBGetSepHeight(ptb, pButton));
- else
- yPos += ptb->iButHeight;
- }
- else // standard horizontal toolbar.
- {
- xPos += TBWidthOfButton(ptb, pButton, NULL) - s_dxOverlap;
- if (pButton->fsState & TBSTATE_WRAP)
- {
- yPos += ptb->iButHeight;
- if (pButton->fsStyle & BTNS_SEP)
- {
- if (ptb->ci.style & CCS_VERT) {
- yPos -= ptb->iButHeight;
- }
- yPos += (TBGetSepHeight(ptb, pButton));
- }
- xPos = ptb->xFirstButton;
- }
- }
- }
- }
- }
- BOOL TB_GetItemRect(PTBSTATE ptb, UINT uButton, LPRECT lpRect)
- {
- int dy = ptb->iButHeight;
- if (uButton >= (UINT)ptb->iNumButtons
- || (ptb->Buttons[uButton].fsState & TBSTATE_HIDDEN))
- {
- return FALSE;
- }
- if (!ptb->fItemRectsValid) {
- TB_CalcItemRects(ptb);
- ptb->fItemRectsValid = TRUE;
- }
- lpRect->left = ptb->Buttons[uButton].pt.x;
- lpRect->right = lpRect->left + TBWidthOfButton(ptb, &ptb->Buttons[uButton], NULL);
- lpRect->top = ptb->Buttons[uButton].pt.y;
- lpRect->bottom = lpRect->top + TBHeightOfButton(ptb, &ptb->Buttons[uButton]);
- return TRUE;
- }
- void InvalidateButton(PTBSTATE ptb, LPTBBUTTONDATA pButtonToPaint, BOOL fErase)
- {
- RECT rc;
- if (TB_GetItemRect(ptb, (UINT) (pButtonToPaint - ptb->Buttons), &rc))
- {
- InvalidateRect(ptb->ci.hwnd, &rc, fErase);
- }
- }
- /*----------------------------------------------------------
- Purpose: Toggles the button as a dropdown
- Returns: TRUE if handled
- */
- BOOL TBToggleDropDown(PTBSTATE ptb, int iPos, BOOL fEatMsg)
- {
- BOOL bRet = FALSE;
- LPTBBUTTONDATA ptbButton = &ptb->Buttons[iPos];
- ASSERT(TB_IsDropDown(ptbButton));
- if (ptbButton->fsState & TBSTATE_ENABLED)
- {
- UINT nVal;
- ptb->iPressedDD = iPos;
- if (TB_HasUnsplitDDArrow(ptb, ptbButton))
- ptbButton->fsState |= TBSTATE_PRESSED;
- InvalidateButton(ptb, ptbButton, TRUE);
- UpdateWindow(ptb->ci.hwnd);
- MyNotifyWinEvent(EVENT_OBJECT_STATECHANGE, ptb->ci.hwnd, OBJID_CLIENT, iPos+1);
- nVal = (UINT) SendItemNotify(ptb, ptbButton->idCommand, TBN_DROPDOWN);
- if (TBDDRET_DEFAULT == nVal || TBDDRET_TREATPRESSED == nVal)
- {
- if (fEatMsg)
- {
- MSG msg;
- PeekMessage(&msg, ptb->ci.hwnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
- }
- ptb->iPressedDD = -1;
- if (TB_HasUnsplitDDArrow(ptb, ptbButton))
- ptbButton->fsState &= ~TBSTATE_PRESSED;
- InvalidateButton(ptb, ptbButton, TRUE);
- UpdateWindow(ptb->ci.hwnd);
- MyNotifyWinEvent(EVENT_OBJECT_STATECHANGE, ptb->ci.hwnd, OBJID_CLIENT, iPos+1);
- }
- bRet = (TBDDRET_DEFAULT == nVal);
- }
- return bRet;
- }
- void TBInvalidateButton(PTBSTATE ptb, int i, BOOL fErase)
- {
- if (i != -1) {
- InvalidateButton(ptb, &ptb->Buttons[i], fErase);
- }
- }
- void TBSetHotItem(PTBSTATE ptb, int iPos, DWORD dwReason)
- {
- HWND hwnd;
- if ((ptb->ci.style & TBSTYLE_FLAT) ) {
- // Either one of these values can be -1, but refrain
- // from processing if both are negative b/c it is wasteful
- // and very common
- if ((ptb->iHot != iPos || (dwReason & HICF_RESELECT)) &&
- (0 <= ptb->iHot || 0 <= iPos) &&
- iPos < ptb->iNumButtons)
- {
- NMTBHOTITEM nmhot = {0};
- // Has the mouse moved away from the toolbar but
- // do we still anchor the highlight?
- if (0 > iPos && ptb->fAnchorHighlight && (dwReason & HICF_MOUSE))
- return ; // Yes; deny the hot item change
- // Send a notification about the hot item change
- if (0 > ptb->iHot)
- {
- if (iPos >= 0)
- nmhot.idNew = ptb->Buttons[iPos].idCommand;
- nmhot.dwFlags = HICF_ENTERING;
- }
- else if (0 > iPos)
- {
- if (ptb->iHot >= 0 && ptb->iHot < ptb->iNumButtons)
- nmhot.idOld = ptb->Buttons[ptb->iHot].idCommand;
- nmhot.dwFlags = HICF_LEAVING;
- }
- else
- {
- if (ptb->iHot < ptb->iNumButtons)
- nmhot.idOld = ptb->Buttons[ptb->iHot].idCommand;
- nmhot.idNew = ptb->Buttons[iPos].idCommand;
- }
- nmhot.dwFlags |= dwReason;
- // must save this for revalidation
- hwnd = ptb->ci.hwnd;
- if (CCSendNotify(&ptb->ci, TBN_HOTITEMCHANGE, &nmhot.hdr))
- return; // deny the hot item change
- // Revalidate the window
- if (!IsWindow(hwnd)) return;
- TBInvalidateButton(ptb, ptb->iHot, TRUE);
- if ((iPos < 0) || !(ptb->Buttons[iPos].fsState & TBSTATE_ENABLED))
- iPos = -1;
- ptb->iHot = iPos;
- if (GetFocus() == ptb->ci.hwnd)
- MyNotifyWinEvent(EVENT_OBJECT_FOCUS, ptb->ci.hwnd, OBJID_CLIENT, iPos + 1);
- TBInvalidateButton(ptb, ptb->iHot, TRUE);
- if ((iPos >= 0 && iPos < ptb->iNumButtons) &&
- (TB_IsDropDown(&ptb->Buttons[iPos])) &&
- (dwReason & HICF_TOGGLEDROPDOWN))
- {
- TBToggleDropDown(ptb, iPos, FALSE);
- }
- }
- }
- }
- BOOL GetInsertMarkRect(PTBSTATE ptb, LPRECT prc, BOOL fHorizMode)
- {
- BOOL fRet = TB_GetItemRect(ptb, ptb->iInsert, prc);
- if (fRet)
- {
- // if we are in horizontal mode, we need a vertical insertion marker
- if ( fHorizMode )
- {
- if (ptb->fInsertAfter)
- prc->left = prc->right;
- else
- prc->right = prc->left;
- prc->left -= INSERTMARKSIZE/2;
- prc->right += INSERTMARKSIZE/2 + 1;
- }
- else
- {
- if (ptb->fInsertAfter)
- prc->top = prc->bottom;
- else
- prc->bottom = prc->top;
- prc->top -= INSERTMARKSIZE/2;
- prc->bottom += INSERTMARKSIZE/2 + 1;
- }
- }
- return fRet;
- }
- void TBInvalidateMark(PTBSTATE ptb)
- {
- RECT rc;
- if (GetInsertMarkRect(ptb, &rc, !(ptb->ci.style & CCS_VERT)))
- {
- InvalidateRect(ptb->ci.hwnd, &rc, TRUE);
- }
- }
- void TBSetInsertMark(PTBSTATE ptb, LPTBINSERTMARK ptbim)
- {
- if (ptbim->iButton != ptb->iInsert ||
- BOOLIFY(ptb->fInsertAfter) != BOOLIFY(ptbim->dwFlags & TBIMHT_AFTER))
- {
- if (ptb->iInsert != -1)
- TBInvalidateMark(ptb);
- ptb->iInsert = ptbim->iButton;
- ptb->fInsertAfter = BOOLIFY(ptbim->dwFlags & TBIMHT_AFTER);
- if (ptb->iInsert != -1)
- TBInvalidateMark(ptb);
- }
- }
- void TBCycleHotItem(PTBSTATE ptb, int iStart, int iDirection, UINT nReason)
- {
- int i;
- int iPrev;
- NMTBWRAPHOTITEM nmwh;
- nmwh.iDir = iDirection;
- nmwh.nReason = nReason;
- //When cycling around the menu, without this check, the second to last menu
- //item would be selected.
- if (iStart == -1 && iDirection == -1)
- iStart = 0;
- for (i = 0; i < ptb->iNumButtons; i++)
- {
- iPrev = iStart;
- iStart += iDirection + ptb->iNumButtons;
- iStart %= ptb->iNumButtons;
- if ( ( iPrev + iDirection >= ptb->iNumButtons) || (iPrev + iDirection < 0) )
- {
- nmwh.iStart = iStart;
- if (CCSendNotify(&ptb->ci, TBN_WRAPHOTITEM, &nmwh.hdr))
- return;
- }
- if (ptb->Buttons[iStart].fsState & TBSTATE_ENABLED &&
- !(ptb->Buttons[iStart].fsState & TBSTATE_HIDDEN) &&
- !(ptb->Buttons[iStart].fsStyle & BTNS_SEP))
- {
- // if the old hot item was dropped down, undrop it.
- if (ptb->iHot != -1 && ptb->iHot == ptb->iPressedDD)
- TBToggleDropDown(ptb, ptb->iHot, FALSE);
- TBSetHotItem(ptb, iStart, nReason);
- break;
- }
- }
- }
- // Do hit testing by sliding the origin of the supplied point
- //
- // returns:
- // >= 0 index of non separator item hit
- // < 0 index of separator or nearest non separator item (area
- // just below and to the left)
- //
- // +--------------------------------------
- // | -1 -1 -1 -1
- // | btn sep btn
- // | +-----+ +-----+
- // | | | | |
- // | -1 | 0 | -1 | 2 | -3
- // | | | | |
- // | +-----+ +-----+
- // |
- // | -1 -1 -1 -2 -3
- //
- int TBHitTest(PTBSTATE ptb, int xPos, int yPos)
- {
- int prev = 0;
- int last = 0;
- int i;
- RECT rc;
- if (ptb->iNumButtons == 0)
- return(-1);
- for (i=0; i<ptb->iNumButtons; i++)
- {
- if (TB_GetItemRect(ptb, i, &rc))
- {
- // ignore this button if hidden because of HideClippedButtons style
- if (!(ptb->dwStyleEx & TBSTYLE_EX_HIDECLIPPEDBUTTONS) || !(TBIsRectClipped(ptb, &rc)))
- {
- // From PtInRect docs:
- // A point is within a rectangle if it lies on the left or top
- // side or is within all four sides. A point on the right or
- // bottom side is considered outside the rectangle.
- if (yPos >= rc.top && yPos < rc.bottom)
- {
- if (xPos >= rc.left && xPos < rc.right)
- {
- if (ptb->Buttons[i].fsStyle & BTNS_SEP)
- return - i - 1;
- else
- return i;
- }
- else
- {
- prev = i + 1;
- }
- }
- else
- {
- last = i;
- }
- }
- }
- }
- if (prev)
- return -1 - prev;
- else if (yPos > rc.bottom)
- // this means that we are off the bottom of the toolbar
- return(- i - 1);
- return last + 1;
- }
- // Same as above except:
- // - returns TRUE if the cursor is on the button edge.
- // - returns FALSE is the cursor is b/t buttons or on the button itself
- BOOL TBInsertMarkHitTest(PTBSTATE ptb, int xPos, int yPos, LPTBINSERTMARK ptbim)
- {
- TBINSERTMARK prev = {-1, TBIMHT_AFTER|TBIMHT_BACKGROUND}; // best guess if we hit a row
- TBINSERTMARK last = {-1, TBIMHT_AFTER|TBIMHT_BACKGROUND}; // best guess if we don't
- int i;
- // restrict hit testing depending upon whether we are vertical or horizontal
- BOOL fHorizMode = !(ptb->ci.style & CCS_VERT);
- for (i=0; i<ptb->iNumButtons; i++)
- {
- RECT rc;
- if (TB_GetItemRect(ptb, i, &rc))
- {
- if (yPos >= rc.top && yPos < rc.bottom)
- {
- if (xPos >= rc.left && xPos < rc.right)
- {
- ptbim->iButton = i;
- if ( fHorizMode )
- {
- if (xPos < rc.left + g_cxEdge*4)
- {
- ptbim->dwFlags = 0;
- return TRUE;
- }
- else if (xPos > rc.right - g_cxEdge*4)
- {
- ptbim->dwFlags = TBIMHT_AFTER;
- return TRUE;
- }
- }
- else
- {
- // vertical....
- if (yPos < rc.top + g_cyEdge*4)
- {
- ptbim->dwFlags = 0;
- return TRUE;
- }
- else if (yPos > rc.bottom - g_cyEdge*4)
- {
- ptbim->dwFlags = TBIMHT_AFTER;
- return TRUE;
- }
- }
- // else we are just on a button...
- ptbim->dwFlags = 0;
- return FALSE;
- }
- else
- {
- if (xPos < rc.left)
- {
- // since buttons are laid out left to right
- // and rows are laid out top to bottom,
- // if we ever hit this case, we can't hit anything else
- ptbim->iButton = i;
- ptbim->dwFlags = TBIMHT_BACKGROUND;
- return FALSE;
- }
- else // (xPos > rc.right)
- {
- // remember the last one we've seen on this row
- prev.iButton = i;
- }
- }
- }
- else
- {
- if (yPos < rc.top)
- {
- if (prev.iButton != -1)
- {
- *ptbim = prev;
- }
- else
- {
- ptbim->iButton = i;
- ptbim->dwFlags = TBIMHT_BACKGROUND;
- }
- }
- else
- {
- // remember the last one we've seen
- last.iButton = i;
- }
- }
- }
- }
- if (prev.iButton != -1)
- *ptbim = prev;
- else
- *ptbim = last;
- return FALSE;
- }
- int CountRows(PTBSTATE ptb)
- {
- LPTBBUTTONDATA pButton, pBtnLast;
- int rows = 1;
- // BUGBUG (scotth): this doesn't look vertical-friendly
- // chrisny: semantically no, technically it will work like a charm :-)
- pBtnLast = &(ptb->Buttons[ptb->iNumButtons]);
- for (pButton = ptb->Buttons; pButton<pBtnLast; pButton++) {
- if (pButton->fsState & TBSTATE_WRAP) {
- rows++;
- if (pButton->fsStyle & BTNS_SEP)
- rows++;
- }
- }
- return rows;
- }
- #define CountCols(ptb) CountRows(ptb)
- void WrapToolbarCol(PTBSTATE ptb, int dy, LPRECT lpRect, int *pCols)
- {
- LPTBBUTTONDATA pButton, pBtnLast, pBtnPrev;
- LPTBBUTTONDATA pbtnLastVisible = NULL;
- LPTBBUTTONDATA pbtnPrev = NULL;
- int xPos, yPos;
- int dyButton;
- int yPosWrap = 0;
- int cCols = 1;
- DEBUG_CODE( int cItemsPerCol = 0; )
- ASSERT(ptb->dwStyleEx & TBSTYLE_EX_VERTICAL);
- TraceMsg(TF_TOOLBAR, "Toolbar: calculating WrapToolbar");
- // dy must be at least the button height, otherwise the final
- // rect is mis-calculated and will be too big.
- if (dy < ptb->iButHeight)
- dy = ptb->iButHeight;
- dyButton = ptb->iButHeight;
- xPos = ptb->xFirstButton;
- yPos = ptb->iYPos;
- pBtnLast = &(ptb->Buttons[ptb->iNumButtons]);
- ptb->szCached.cx = -1;
- ptb->szCached.cy = -1;
- if (pCols)
- (*pCols) = 1;
- pBtnPrev = ptb->Buttons;
- for (pButton = ptb->Buttons; pButton < pBtnLast; pButton++)
- {
- DEBUG_CODE( cItemsPerCol++; )
- // we nuke the wrap state at the start of the loop.
- // so we don't know if/when we are adding on a wrap bit that wasn't there
- // before. we overstep the button, then back up when we've gone too far,
- pButton->fsState &= ~TBSTATE_WRAP;
- if (!(pButton->fsState & TBSTATE_HIDDEN))
- {
- if (pButton->fsStyle & BTNS_SEP)
- yPos += (TBGetSepHeight(ptb, pButton));
- else
- yPos += dyButton;
- // Is this button out of bounds?
- if (yPos > dy)
- {
- // Yes; wrap it.
- if ((pButton->fsStyle & BTNS_SEP) &&
- yPos - TBGetSepHeight(ptb, pButton) > yPosWrap)
- {
- yPosWrap = yPos - TBGetSepHeight(ptb, pButton); // wrap at first in next col.
- }
- else if (yPos - dyButton > yPosWrap)
- yPosWrap = yPos - dyButton; // wrap at first in next col.
- if (xPos + ptb->iButWidth <= ptb->sizeBound.cx)
- xPos += ptb->iButWidth;
- yPos = dyButton;
- cCols++;
- pBtnPrev->fsState |= TBSTATE_WRAP;
- DEBUG_CODE( cItemsPerCol = 0; )
- }
- // button in bounds gets handled above.
- pBtnPrev = pButton; // save previous for wrap point
- }
- }
- yPos = yPosWrap ? yPosWrap : yPos;
- if (pCols)
- *pCols = cCols;
- ptb->rc.left = 0;
- ptb->rc.right = xPos + ptb->iButWidth;
- ptb->rc.top = 0;
- ptb->rc.bottom = yPos;
- if (lpRect)
- CopyRect(lpRect, &ptb->rc);
- InvalidateRect(ptb->ci.hwnd, NULL, TRUE);
- }
- /**** WrapToolbar: * The buttons in the toolbar is layed out from left to right,
- * top to bottom. If adding another button to the current row,
- * while computing the layout, would cause that button to extend
- * beyond the right edge or the client area, then locate a break-
- * point (marked with the TBSTATE_WRAP flag). A break-point is:
- *
- * a) The right-most separator on the current row.
- *
- * b) The right-most button if there is no separator on the current row.
- *
- * A new row is also started at the end of any button group (sequence
- * of buttons that are delimited by separators) that are taller than
- * or equal to two rows.
- */
- void WrapToolbar(PTBSTATE ptb, int dx, LPRECT lpRect, int *pRows)
- {
- BOOL fInvalidate = FALSE;
- LPTBBUTTONDATA pButton, pBtnT, pBtnLast;
- LPTBBUTTONDATA pbtnLastVisible = NULL;
- LPTBBUTTONDATA pbtnPrev = NULL;
- BOOL fLastVisibleWrapped = FALSE;
- int xPos, yPos, xMax;
- int dyButton;
- BOOL bWrapAtNextSeparator = FALSE;
- ASSERT(!(ptb->dwStyleEx & TBSTYLE_EX_VERTICAL));
- TraceMsg(TF_TOOLBAR, "Toolbar: calculating WrapToolbar");
- if (ptb->iNumButtons == 0) {
- // no buttons, so we're not going to go through the loop below; initialize
- // dyButton to 0 so that we fill in lpRect with 0 height. this fixes ideal
- // size calculation for empty toolbars (NT5 #180430)
- dyButton = 0;
- } else {
- if (dx < ptb->iButWidth) {
- // dx must be at least the button width, otherwise the final
- // rect is mis-calculated and will be too big.
- dx = ptb->iButWidth;
- }
- dyButton = ptb->iButHeight;
- }
- xMax = 0;
- xPos = ptb->xFirstButton;
- yPos = ptb->iYPos;
- pBtnLast = &(ptb->Buttons[ptb->iNumButtons]);
- ptb->szCached.cx = -1;
- ptb->szCached.cy = -1;
- if (pRows)
- (*pRows)=1;
- for (pButton = ptb->Buttons; pButton < pBtnLast; pButton++)
- {
- // we nuke the wrap state at the start of the loop.
- // so we don't know if/when we are adding on a wrap bit that wasn't there
- // before. we overstep the button, then back up when we've gone too far,
- // so we can't simply keep the at the start of the loop
- // we need to keep it over to the next iteration
- BOOL fNextLastVisibleWrapped = (pButton->fsState & TBSTATE_WRAP);
- LPTBBUTTONDATA pbtnSav = pButton;
- pButton->fsState &= ~TBSTATE_WRAP;
- if (!(pButton->fsState & TBSTATE_HIDDEN))
- {
- LPTBBUTTONDATA pbtnNextLastVisible = pButton;
- xPos += TBWidthOfButton(ptb, pButton, NULL) - s_dxOverlap;
- // Is this a normal button and is the button out of bounds?
- if (!(pButton->fsStyle & BTNS_SEP) && (xPos > dx)) {
- // Yes; wrap it. Go back to the first non-hidden separator
- // as a break-point candidate.
- for (pBtnT=pButton;
- pBtnT>ptb->Buttons && !(pBtnT->fsState & TBSTATE_WRAP);
- pBtnT--)
- {
- if ((pBtnT->fsStyle & BTNS_SEP) &&
- !(pBtnT->fsState & TBSTATE_HIDDEN))
- {
- yPos += (TBGetSepHeight(ptb, pBtnT)) + dyButton;
- bWrapAtNextSeparator = FALSE;
- if (pRows)
- (*pRows)++;
- goto SetWrapHere;
- }
- }
- pBtnT = pButton;
- // Are we at the first button?
- if (pButton != ptb->Buttons) {
- // No; back up to first non-hidden button
- do {
- pBtnT--;
- } while ((pBtnT>ptb->Buttons) &&
- (pBtnT->fsState & TBSTATE_HIDDEN));
- // Is it already wrapped?
- if (pBtnT->fsState & TBSTATE_WRAP)
- {
- // Yes; wrap the button we were looking at originally
- pBtnT = pButton;
- }
- }
- // Wrap at the next separator because we've now wrapped in the middle
- // of a group of buttons.
- bWrapAtNextSeparator = TRUE;
- yPos += dyButton;
- SetWrapHere:
- pBtnT->fsState |= TBSTATE_WRAP;
- // find out if this wrap bit is new...
- // it isn't if this button was the last visible button
- // and that last visible button started off wrapped
- if (pBtnT != pbtnLastVisible || !fLastVisibleWrapped)
- fInvalidate = TRUE;
- xPos = ptb->xFirstButton;
- pButton = pBtnT;
- // Count another row.
- if (pRows)
- (*pRows)++;
- }
- else
- {
- // No; this is a separator (in or out of bounds) or a button that is in-bounds.
- if (pButton->fsStyle & BTNS_SEP)
- {
- if (ptb->ci.style & CCS_VERT)
- {
- if (pbtnPrev && !(pbtnPrev->fsState & TBSTATE_WRAP))
- {
- pbtnPrev->fsState |= TBSTATE_WRAP;
- yPos += dyButton;
- }
- xPos = ptb->xFirstButton;
- yPos += TBGetSepHeight(ptb, pButton);
- pButton->fsState |= TBSTATE_WRAP;
- if (pRows)
- (*pRows)++;
- }
- else if (bWrapAtNextSeparator)
- {
- bWrapAtNextSeparator = FALSE;
- pButton->fsState |= TBSTATE_WRAP;
- xPos = ptb->xFirstButton;
- yPos += dyButton + (TBGetSepHeight(ptb, pButton));
- if (pRows)
- (*pRows)+=2;
- }
- }
- // This button is visible and it's one we cached at the top of the loop
- // set it for the next loop
- if (pButton == pbtnNextLastVisible) {
- ASSERT(!(pButton->fsState & TBSTATE_HIDDEN));
- if (!(pButton->fsState & TBSTATE_HIDDEN)) {
- // we don't know that we're not going to re-wrap an item that was initially wrapped
- // until this point
- if (pbtnLastVisible && fLastVisibleWrapped && !(pbtnLastVisible->fsState & TBSTATE_WRAP))
- fInvalidate = TRUE;
- pbtnLastVisible = pButton;
- fLastVisibleWrapped = fNextLastVisibleWrapped;
- }
- }
- }
- if (!(pButton->fsStyle&BTNS_SEP))
- xMax = max(xPos, xMax);
- pbtnPrev = pbtnSav;
- }
- }
- if (lpRect)
- {
- lpRect->left = 0;
- lpRect->right = xMax;
- lpRect->top = 0;
- lpRect->bottom = yPos + ptb->iYPos + dyButton;
- }
- if (fInvalidate)
- InvalidateRect(ptb->ci.hwnd, NULL, TRUE);
- }
- // only called from TB_SETROWS so no worry's about TBSTYLE_EX_MULTICOLUMN
- BOOL BoxIt(PTBSTATE ptb, int height, BOOL fLarger, LPRECT lpRect)
- {
- int dx, bwidth;
- int rows, prevRows, prevWidth;
- RECT rcCur;
- if (height<1)
- height = 1;
- rows = CountRows(ptb);
- if (height==rows || ptb->iNumButtons==0)
- {
- GetClientRect(ptb->ci.hwnd, lpRect);
- return FALSE;
- }
- bwidth = ptb->iButWidth-s_dxOverlap;
- prevRows = ptb->iNumButtons+1;
- prevWidth = bwidth;
- for (rows=height+1, dx = bwidth; rows>height;dx+=bwidth/4)
- {
- WrapToolbar(ptb, dx, &rcCur, &rows);
- if (rows<prevRows && rows>height)
- {
- prevWidth = dx;
- prevRows = rows;
- }
- }
- if (rows<height && fLarger)
- {
- WrapToolbar(ptb, prevWidth, &rcCur, NULL);
- }
- if (lpRect)
- *lpRect = rcCur;
- return TRUE;
- }
- int PositionFromID(PTBSTATE ptb, LONG_PTR id)
- {
- int i;
- // Handle case where this is sent at the wrong time..
- if (ptb == NULL || id == -1)
- return -1;
- // note, we don't skip separators, so you better not have conflicting
- // cmd ids and separator ids.
- for (i = 0; i < ptb->iNumButtons; i++)
- if (ptb->Buttons[i].idCommand == id)
- return i; // position found
- return -1; // ID not found!
- }
- // check a radio button by button index.
- // the button matching idCommand was just pressed down. this forces
- // up all other buttons in the group.
- // this does not work with buttons that are forced up with
- void MakeGroupConsistant(PTBSTATE ptb, int idCommand)
- {
- int i, iFirst, iLast, iButton;
- int cButtons = ptb->iNumButtons;
- LPTBBUTTONDATA pAllButtons = ptb->Buttons;
- iButton = PositionFromID(ptb, idCommand);
- if (iButton < 0)
- return;
- // assertion
- // if (!(pAllButtons[iButton].fsStyle & BTNS_CHECK))
- // return;
- // did the pressed button just go down?
- if (!(pAllButtons[iButton].fsState & TBSTATE_CHECKED))
- return; // no, can't do anything
- // find the limits of this radio group
- // there was a bug here since win95 days -- ; there was no ; at the end of for loop
- // and if was part of it -- some apps may rely on that (reljai 6/16/98)
- for (iFirst = iButton; (iFirst > 0) && (pAllButtons[iFirst].fsStyle & BTNS_GROUP); iFirst--);
- if (!(pAllButtons[iFirst].fsStyle & BTNS_GROUP))
- iFirst++;
- cButtons--;
- for (iLast = iButton; (iLast < cButtons) && (pAllButtons[iLast].fsStyle & BTNS_GROUP); iLast++);
- if (!(pAllButtons[iLast].fsStyle & BTNS_GROUP))
- iLast--;
- // search for the currently down button and pop it up
- for (i = iFirst; i <= iLast; i++) {
- if (i != iButton) {
- // is this button down?
- if (pAllButtons[i].fsState & TBSTATE_CHECKED) {
- pAllButtons[i].fsState &= ~TBSTATE_CHECKED; // pop it up
- TBInvalidateButton(ptb, i, TRUE);
- break; // only one button is down right?
- }
- }
- }
- }
- void DestroyStrings(PTBSTATE ptb)
- {
- PTSTR *p;
- PTSTR end = 0, start = 0;
- int i;
- p = ptb->pStrings;
- for (i = 0; i < ptb->nStrings; i++) {
- if (!((*p < end) && (*p > start))) {
- start = (*p);
- end = start + (LocalSize((HANDLE)*p) / sizeof(TCHAR));
- LocalFree((HANDLE)*p);
- }
- p++;
- }
- LocalFree((HANDLE)ptb->pStrings);
- }
- // gets the iString from pStrings and copies it to pszText.
- // returns the lstrlen.
- // pszText can be null to just fetch the length.
- int TBGetString(PTBSTATE ptb, int iString, int cchText, LPTSTR pszText)
- {
- int iRet = -1;
- if (iString < ptb->nStrings) {
- iRet = lstrlen(ptb->pStrings[iString]);
- if (pszText) {
- lstrcpyn(pszText, ptb->pStrings[iString], cchText);
- }
- }
- return iRet;
- }
- #ifdef UNICODE
- // gets the iString from pStrings and copies it to pszText.
- // returns the lstrlen.
- // pszText can be null to just fetch the length.
- int TBGetStringA(PTBSTATE ptb, int iString, int cchText, LPSTR pszText)
- {
- int iRet = -1;
- if (iString < ptb->nStrings) {
- iRet = lstrlenW(ptb->pStrings[iString]);
- if (pszText) {
- WideCharToMultiByte (CP_ACP, 0, ptb->pStrings[iString],
- -1, pszText, cchText, NULL, NULL);
- }
- }
- return iRet;
- }
- #endif
- #define MAXSTRINGSIZE 1024
- int TBAddStrings(PTBSTATE ptb, WPARAM wParam, LPARAM lParam)
- {
- int i = 0,j = 0, cxMax = 0;
- LPTSTR lpsz;
- PTSTR pString, pStringAlloc, psz;
- int numstr;
- PTSTR *pFoo;
- PTSTR *pOffset;
- TCHAR cSeparator;
- int len;
- // read the string as a resource
- if (wParam != 0) {
- pString = (PTSTR)LocalAlloc(LPTR, (MAXSTRINGSIZE * sizeof (TCHAR)));
- if (!pString)
- return -1;
- i = LoadString((HINSTANCE)wParam, LOWORD(lParam), (LPTSTR)pString, MAXSTRINGSIZE);
- if (!i) {
- LocalFree(pString);
- return -1;
- }
- // realloc string buffer to actual needed size
- psz = LocalReAlloc(pString, (i+1) * sizeof (TCHAR), LMEM_MOVEABLE);
- if (psz)
- pString = psz;
- // convert separators to '' and count number of strings
- cSeparator = *pString;
- #ifndef UNICODE
- for (numstr = 0, psz = pString + 1, i--; i; i--, psz++ ) {
- if (*psz == cSeparator) {
- if (i != 1) // We don't want to count the second terminator as another string
- numstr++;
- *psz = 0; // terminate with 0
- }
- // extra i-- if DBCS
- if (IsDBCSLeadByte(*psz))
- {
- *(WORD *)(psz-1) = *(WORD *)psz;
- psz++;
- i--;
- }
- else
- {
- // shift string to the left to overwrite separator identifier
- *(psz - 1) = *psz;
- }
- }
- #else
- for (numstr = 0, psz = pString + 1, i--; i; i--, psz++) {
- if (*psz == cSeparator) {
- if (i != 1) // We don't want to count the second terminator as another string
- numstr++;
- *psz = 0; // terminate with 0
- }
- // shift string to the left to overwrite separator identifier
- *(psz - 1) = *psz;
- }
- #endif
- }
- // read explicit string. copy it into local memory, too.
- else {
- // Common mistake is to forget to check the return value of
- // LoadLibrary and accidentally pass wParam=NULL.
- if (IS_INTRESOURCE(lParam))
- return -1;
- // find total length and number of strings
- for (i = 0, numstr = 0, lpsz = (LPTSTR)lParam;;) {
- i++;
- if (*lpsz == 0) {
- numstr++;
- if (*(lpsz + 1) == 0)
- break;
- }
- lpsz++;
- }
- pString = (PTSTR)LocalAlloc(LPTR, (i * sizeof (TCHAR)));
- if (!pString)
- return -1;
- hmemcpy(pString, (void *)lParam, i * sizeof(TCHAR));
- }
- pStringAlloc = pString; // in case something bad happens
- // make room for increased string pointer table
- pFoo = (PTSTR *)CCLocalReAlloc(ptb->pStrings,
- (ptb->nStrings + numstr) * sizeof(PTSTR));
- if (!pFoo) {
- goto Failure;
- }
- ptb->pStrings = pFoo;
- // pointer to next open slot in string index table.
- pOffset = ptb->pStrings + ptb->nStrings;
- for (i = 0; i < numstr; i++, pOffset++)
- {
- *pOffset = pString;
- len = lstrlen(pString);
- pString += len + 1;
- }
- // is the world big enough to handle the larger buttons?
- i = ptb->nStrings;
- ptb->nStrings += numstr;
- if (!TBRecalc(ptb))
- {
- ptb->nStrings -= numstr;
- // back out changes.
- pFoo = (PTSTR *)CCLocalReAlloc(ptb->pStrings,
- ptb->nStrings * sizeof(PTSTR));
- if (pFoo)
- ptb->pStrings = pFoo;
- // don't get mad if pFoo == NULL; it means the shrink failed, no big deal
- Failure:
- LocalFree(pStringAlloc);
- return -1;
- }
- return i; // index of first added string
- }
- void MapToStandardBitmaps(HINSTANCE *phinst, UINT_PTR *pidBM, int *pnButtons)
- {
- if (*phinst == HINST_COMMCTRL) {
- *phinst = g_hinst;
- // low 2 bits are coded M(mono == ~color) L(large == ~small)
- // 0 0 -> color small
- // 0 1 -> color large
- // ...
- // 1 1 -> mono large
- switch (*pidBM)
- {
- case IDB_STD_SMALL_COLOR:
- case IDB_STD_LARGE_COLOR:
- case IDB_STD_SMALL_MONO:
- case IDB_STD_LARGE_MONO:
- *pidBM = IDB_STDTB_SMALL_COLOR + (*pidBM & 1);
- *pnButtons = STD_PRINT + 1;
- break;
- case IDB_HIST_SMALL_COLOR:
- case IDB_HIST_LARGE_COLOR:
- //case IDB_HIST_SMALL_MONO:
- //case IDB_HIST_LARGE_MONO:
- *pidBM = IDB_HISTTB_SMALL_COLOR + (*pidBM & 1);
- *pnButtons = HIST_LAST + 1;
- break;
- case IDB_VIEW_SMALL_COLOR:
- case IDB_VIEW_LARGE_COLOR:
- case IDB_VIEW_SMALL_MONO:
- case IDB_VIEW_LARGE_MONO:
- *pidBM = IDB_VIEWTB_SMALL_COLOR + (*pidBM & 1);
- *pnButtons = VIEW_NEWFOLDER + 1;
- break;
- }
- }
- }
- //
- // the PBITMAP points to the BITMAP structure that was GetObject'd from
- // the hbm, except that pbm->bmWidth and pbm->bmHeight have been adjusted
- // to represent the *desired* height and width, not the actual height
- // and width.
- //
- HBITMAP _CopyBitmap(PTBSTATE ptb, HBITMAP hbm, PBITMAP pbm)
- {
- HBITMAP hbmCopy = NULL;
- HDC hdcWin;
- HDC hdcSrc, hdcDest;
- // Old code called CreateColorBitmap, which is bad on multimon systems
- // because it will create a bitmap that ImageList_AddMasked can't handle,
- // resulting in disabled toolbar buttons looking like crap.
- // so we have to create the bitmap copy in the same format as the source
- hdcWin = GetDC(ptb->ci.hwnd);
- hdcSrc = CreateCompatibleDC(hdcWin);
- hdcDest = CreateCompatibleDC(hdcWin);
- if (hdcWin && hdcSrc && hdcDest) {
- SelectObject(hdcSrc, hbm);
- if (pbm->bmBits) {
- // Source was a DIB section. Create a DIB section in the same
- // color format with the same palette.
- //
- // Man, creating a DIB section is so annoying.
- struct { // Our private version of BITMAPINFO
- BITMAPINFOHEADER bmiHeader;
- RGBQUAD bmiColors[256];
- } bmi;
- UINT cBitsPixel;
- LPVOID pvDummy;
- ZeroMemory(&bmi.bmiHeader, sizeof(bmi.bmiHeader));
- bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
- bmi.bmiHeader.biWidth = pbm->bmWidth;
- bmi.bmiHeader.biHeight = pbm->bmHeight;
- bmi.bmiHeader.biPlanes = 1;
- // DIB color depths must be exactly 1, 4, 8 or 24.
- cBitsPixel = pbm->bmPlanes * pbm->bmBitsPixel;
- if (cBitsPixel <= 1)
- bmi.bmiHeader.biBitCount = 1;
- else if (cBitsPixel <= 4)
- bmi.bmiHeader.biBitCount = 4;
- else if (cBitsPixel <= 8)
- bmi.bmiHeader.biBitCount = 8;
- else
- goto CreateDDB; // ImageList_AddMasked doesn't like DIBs deeper than 8bpp
- // And get the color table too
- ASSERT(bmi.bmiHeader.biBitCount <= 8);
- bmi.bmiHeader.biClrUsed = GetDIBColorTable(hdcSrc, 0, 1 << bmi.bmiHeader.biBitCount, bmi.bmiColors);
- ASSERT(bmi.bmiHeader.biCompression == BI_RGB);
- ASSERT(bmi.bmiHeader.biSizeImage == 0);
- hbmCopy = CreateDIBSection(hdcWin, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &pvDummy, NULL, 0);
- } else {
- // Source was a DDB. Create a duplicate DDB.
- CreateDDB:
- // Since the caller may have dorked the bmWidth,
- // we have to recompute the bmWidthBytes, because GDI
- // gets mad if it's not exactly right, even in the bmBits == NULL
- // case.
- pbm->bmBits = NULL;
- pbm->bmWidthBytes = ((pbm->bmBitsPixel * pbm->bmWidth + 15) >> 4) << 1;
- hbmCopy = CreateBitmapIndirect(pbm);
- }
- SelectObject(hdcDest, hbmCopy);
- // fill the background
- PatB(hdcDest, 0, 0, pbm->bmWidth, pbm->bmHeight, g_clrBtnFace);
- BitBlt(hdcDest, 0, 0, pbm->bmWidth, pbm->bmHeight,
- hdcSrc, 0, 0, SRCCOPY);
- }
- if (hdcWin)
- ReleaseDC(ptb->ci.hwnd, hdcWin);
- if (hdcSrc)
- DeleteDC(hdcSrc);
- if (hdcDest)
- DeleteDC(hdcDest);
- return hbmCopy;
- }
- BOOL TBAddBitmapToImageList(PTBSTATE ptb, PTBBMINFO pTemp)
- {
- HBITMAP hbm = NULL, hbmTemp = NULL;
- HIMAGELIST himl = TBGetImageList(ptb, HIML_NORMAL, 0);
- if (!himl) {
- himl = ImageList_Create(ptb->iDxBitmap, ptb->iDyBitmap, ILC_MASK | ILC_COLORDDB, 4, 4);
- if (!himl)
- return(FALSE);
- TBSetImageList(ptb, HIML_NORMAL, 0, himl);
- ImageList_SetBkColor(himl, (ptb->ci.style & TBSTYLE_TRANSPARENT) ? CLR_NONE : g_clrBtnFace);
- }
- if (pTemp->hInst) {
- // can't use LoadImage(..., LR_MAP3DCOLORS) - more than 3 colors
- hbm = hbmTemp = CreateMappedBitmap(pTemp->hInst, pTemp->wID, CMB_DIBSECTION, NULL, 0);
- } else if (pTemp->wID) {
- hbm = (HBITMAP)pTemp->wID;
- }
- if (hbm) {
- //
- // Fix up bitmaps that aren't iDxBitmap x iDyBitmap
- //
- BITMAP bm;
- GetObject( hbm, sizeof(bm), &bm);
- if (bm.bmWidth < ptb->iDxBitmap) {
- bm.bmWidth = ptb->iDxBitmap;
- }
- if (bm.bmHeight < ptb->iDyBitmap) {
- bm.bmHeight = ptb->iDyBitmap;
- }
- // The error cases we are catching are:
- // If the pTemp->nButtons is 0 then we assume there is one button
- // If width of the bitmap is less than what it is supposed to be, we fix it.
- if (!pTemp->nButtons)
- bm.bmWidth = ptb->iDxBitmap;
- else if (pTemp->nButtons > (bm.bmWidth / ptb->iDxBitmap))
- bm.bmWidth = ptb->iDxBitmap * pTemp->nButtons;
- // Must preserve color depth to keep ImageList_AddMasked happy
- // And if we started with a DIB section, then create a DIB section.
- // (Curiously, CopyImage does not preserve DIB-ness.)
- hbm = (HBITMAP)_CopyBitmap(ptb, hbm, &bm);
- }
- // AddMasked parties on the bitmap, so we want to use a local copy
- if (hbm) {
- ImageList_AddMasked(himl, hbm, g_clrBtnFace);
- DeleteObject(hbm);
- }
- if (hbmTemp) {
- DeleteObject(hbmTemp);
- }
- return(TRUE);
- }
- void TBBuildImageList(PTBSTATE ptb)
- {
- int i;
- PTBBMINFO pTemp;
- HIMAGELIST himl;
- ptb->fHimlValid = TRUE;
- // is the parent dealing natively with imagelists? if so,
- // don't do this back compat building
- if (ptb->fHimlNative)
- return;
- himl = TBSetImageList(ptb, HIML_NORMAL, 0, NULL);
- ImageList_Destroy(himl);
- for (i = 0, pTemp = ptb->pBitmaps; i < ptb->nBitmaps; i++, pTemp++) {
- TBAddBitmapToImageList(ptb, pTemp);
- }
- }
- /* Adds a new bitmap to the list of BMs available for this toolbar.
- * Returns the index of the first button in the bitmap or -1 if there
- * was an error.
- */
- int AddBitmap(PTBSTATE ptb, int nButtons, HINSTANCE hBMInst, UINT_PTR idBM)
- {