Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

671 lines
20 KiB

/////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
//
// MODULE: BtnBar.cpp
//
// PURPOSE: Implements a generic button bar.
//
#include "_apipch.h"
#define idtTrack 101
#define idcFolderList 102
#define HOTTRACK_TIMER 100
#define ID_HWNDBAR 2020
extern LPIMAGELIST_LOADIMAGE gpfnImageList_LoadImage;
//#define DEAD
void CBB_ConfigureRects(HWND hwnd);
void CBB_DoHotTracking(HWND hwnd);
void CBB_EndHotTracking(HWND hwnd);
int CBB_HitTest(int x, int y);
void CBB_SetSelBtn(int iSel,HWND hwnd);
//
// FUNCTION: CButtonBar::~CButtonBar()
//
// PURPOSE: Cleans up the resources we allocated during the life of the
// object.
//
void CBB_Cleanup(void)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
// Free the GDI resources.
ImageList_Destroy(m_himlButtons);
DeleteObject(m_hpalBkgnd);
DeleteObject(m_hfButton);
DeleteObject(m_hbmpBkgnd);
// Free the button array.
LocalFreeAndNull((LPVOID *)&m_rgButtons);
// NOTE - this is a comment from the original athena source code
//$REVIEW - we can't do this here, because it screws up
// when we have multiple instances of the CButtonBar
// with overlapping creates and destroys. we should
// probably unregister somewhere, but it isn't strictly
// necessary. (EricAn)
// Unregister our window class.
// UnregisterClass(c_szButtonBar, m_hInstance);
return;
}
//
// FUNCTION: CButtonBar::Create()
//
// PURPOSE: Initializes the button bar and creates the button bar window.
//
// PARAMETERS:
// hwndParent - Handle of the window that will be the button bar parent.
// idHwnd - Child window ID for the button bar.
// idButtons - ID of the button icons bitmap.
// idHorzBackground - ID of the horizontal background bitmap.
// idVertBackground - ID of the vertical background bitmap.
// pBtnCreateParams - Pointer to the array of BTNCREATEPARAMS used to create the buttons.
// cParams - Number of buttons in pBtnCreateParams.
// uSide - Side of the parent window the bar should initially attach to.
//
// RETURN VALUE:
// Returns TRUE if successful, or FALSE otherwise.
//
HWND CBB_Create(HWND hwndParent, UINT idButtons,
UINT idHorzBackground,
PBTNCREATEPARAMS pBtnCreateParams, UINT cParams)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
int i;
WNDCLASS wc;
BITMAP bm;
RECT rc;
POINT ptL, ptR;
ICONMETRICS im;
HWND hwnd = NULL;
wc.style = CS_DBLCLKS; // Bug #15450
wc.lpfnWndProc = CBB_ButtonBarProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(LPVOID);
wc.hInstance = hinstMapiX;
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = 0;
wc.lpszMenuName = 0;
wc.lpszClassName = c_szButtonBar;
RegisterClass(&wc);
m_rgButtons = NULL;
m_himlButtons = 0;
m_hbmpBkgnd = 0;
m_hpalBkgnd = 0;
m_hfButton = 0;
m_cButtons = 0;
m_iSelect = -1;
m_iOldSelect = -1;
// This is the information we'll need later to to draw the button bar etc.
// Stash it away for now.
m_cButtons = cParams;
m_rgButtons = LocalAlloc(LMEM_ZEROINIT, sizeof(BUTTON) * m_cButtons);
if (!m_rgButtons) return FALSE;
for (i = 0; i < m_cButtons; i++)
{
m_rgButtons[i].id = pBtnCreateParams[i].id;
m_rgButtons[i].iIcon = pBtnCreateParams[i].iIcon;
LoadString(hinstMapiX, pBtnCreateParams[i].idsLabel,
m_rgButtons[i].szTitle, sizeof(m_rgButtons[i].szTitle));
}
// Load the bitmaps we'll need for drawing.
m_himlButtons = gpfnImageList_LoadImage(hinstMapiX, MAKEINTRESOURCE(idButtons),
c_cxButtons, 0, c_crMask, IMAGE_BITMAP,
0); //LR_LOADMAP3DCOLORS);
if (!m_himlButtons)
return (FALSE);
// Get the width of the bitmap we're going to use as the background so we
// know how wide to make the window.
if (!LoadBitmapAndPalette(idHorzBackground, &m_hbmpBkgnd, &m_hpalBkgnd))
return (FALSE);
if (!GetObject(m_hbmpBkgnd, sizeof(BITMAP), (LPVOID) &bm))
return (FALSE);
GetClientRect(hwndParent, &rc);
// Get the font we're going to use for the buttons
im.cbSize = sizeof(ICONMETRICS);
SystemParametersInfo(SPI_GETICONMETRICS, 0, (LPVOID) &im, 0);
m_hfButton = CreateFontIndirect(&(im.lfFont));
if (!m_hfButton)
return (FALSE);
ptL.x = ptL.y=0;
ptR.x = rc.right;
ptR.y = bm.bmHeight;
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
c_szButtonBar,
c_szButtonBar,
WS_CLIPSIBLINGS |
WS_VISIBLE |
WS_CHILD,
ptL.x,
ptL.y,
ptR.x,
ptR.y,
hwndParent,
(HMENU) ID_HWNDBAR,
hinstMapiX,
NULL);
CBB_ConfigureRects(hwnd);
return (hwnd);
}
//
// FUNCTION: CButtonBar::ButtonBarProc()
//
// PURPOSE: Message handler for the button bar window.
//
LRESULT CALLBACK CBB_ButtonBarProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_NCCREATE:
SetWindowLong(hwnd, 0, (LONG) ((LPCREATESTRUCT) lParam)->lpCreateParams);
return (TRUE);
/***
case WM_CREATE:
return 0;
break;
case WM_SIZE:
return 0;
break;
case WM_LBUTTONDOWN:
return 0;
break;
case WM_COMMAND:
return 0;
break;
/***/
case WM_PAINT:
CBB_OnPaint(hwnd);
return 0;
break;
case WM_MOUSEMOVE:
CBB_OnMouseMove(hwnd, LOWORD(lParam), HIWORD(lParam), wParam);
return 0;
break;
case WM_LBUTTONUP:
CBB_OnLButtonUp(hwnd, LOWORD(lParam), HIWORD(lParam), wParam);
return 0;
break;
case WM_TIMER:
CBB_OnTimer(hwnd, wParam);
return 0;
break;
case WM_MOUSEACTIVATE:
CBB_OnMouseActivate(hwnd, (HWND) wParam, (INT) LOWORD(lParam), (UINT) HIWORD(lParam));
return 0;
break;
case WM_PALETTECHANGED:
if ((HWND) wParam != hwnd)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
HDC hdc = GetDC(hwnd);
HPALETTE hPalOld = SelectPalette(hdc, m_hpalBkgnd, TRUE);
RealizePalette(hdc);
InvalidateRect(hwnd, NULL, TRUE);
SelectPalette(hdc, hPalOld, TRUE);
ReleaseDC(hwnd, hdc);
}
return 0;
}
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
}
void CBB_OnPaint(HWND hwnd)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
HDC hdc;
PAINTSTRUCT ps;
BITMAP bm;
HDC hdcMem;
HBITMAP hbmMemOld, hbmMem;
HPALETTE hpalOld;
RECT rc;
HFONT hf;
COLORREF clrText, clrBk;
int cxIndent = 3;
int cyIndent = 3;
int nTop = 0;
int nLeft = 0;
int nButton = 0;
int i=0;
if(!hwnd) goto out;
// Get the size of the background bitmap
GetObject(m_hbmpBkgnd, sizeof(BITMAP), (LPVOID) &bm);
GetClientRect(hwnd, &rc);
hdc = BeginPaint(hwnd, &ps);
hdcMem = CreateCompatibleDC(hdc);
// If we are displaying the buttons ...
{
// Draw the background bitmaps first.
hpalOld = SelectPalette(hdc, m_hpalBkgnd, TRUE);
RealizePalette(hdc);
hbmMemOld = (HBITMAP) SelectObject(hdcMem, (HGDIOBJ) m_hbmpBkgnd);
// If the window is taller or wider than a single bitmap, we may have
// to loop and put a couple out there.
while (nLeft < rc.right)
{
BitBlt(hdc, nLeft, nTop, bm.bmWidth, bm.bmHeight, hdcMem, 0,
0, SRCCOPY);
nLeft += bm.bmWidth;
}
// Now draw the buttons
nTop = 0;
hf = (HFONT) SelectObject(hdc, m_hfButton);
SetBkMode(hdc, TRANSPARENT);
while (nButton < m_cButtons)
{
if (RectVisible(hdc, &(m_rgButtons[nButton].rcBound)))
{
ImageList_Draw(m_himlButtons, m_rgButtons[nButton].iIcon, hdc,
m_rgButtons[nButton].rcIcon.left, m_rgButtons[nButton].rcIcon.top,
ILD_TRANSPARENT);
// Draw the title of the button that the mouse is over with a
// different color.
if (nButton == m_iSelect)
{
clrBk = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
clrText = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else
{
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
}
SetTextAlign(hdc, TA_TOP /* | TA_CENTER */);
if (nButton == m_iSelect)
{
clrText = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
ExtTextOut( hdc,
(m_rgButtons[nButton].rcTitle.right - m_rgButtons[nButton].rcTitle.left) / 2 + m_rgButtons[nButton].rcTitle.left,
m_rgButtons[nButton].rcTitle.top,
ETO_OPAQUE | ETO_CLIPPED,
&(m_rgButtons[nButton].rcTitle),
m_rgButtons[nButton].szTitle,
lstrlen(m_rgButtons[nButton].szTitle),
NULL);
clrText = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
DrawText(hdc, m_rgButtons[nButton].szTitle, lstrlen(m_rgButtons[nButton].szTitle),
&m_rgButtons[nButton].rcTitle, DT_CENTER | DT_WORDBREAK);
}
else
{
DrawText(hdc, m_rgButtons[nButton].szTitle, lstrlen(m_rgButtons[nButton].szTitle),
&m_rgButtons[nButton].rcTitle, DT_CENTER | DT_WORDBREAK);
}
if (nButton == m_iSelect)
{
SetBkColor(hdc,clrBk);
SetTextColor(hdc, clrText);
}
}
nButton++;
}
SelectObject(hdc, m_hfButton);
if (hpalOld != NULL)
SelectPalette(hdc, hpalOld, TRUE);
SelectObject(hdcMem, hbmMemOld);
}
DeleteObject(hbmMem);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
out:
return;
}
//
// FUNCTION: CButtonBar::OnLButtonUp()
//
// PURPOSE: If we are dragging the button bar around, then the user has
// released the bar and we can clean up. If the user wasn't
// dragging, then they have clicked on a button and we send the
// appropriate command message to the parent window.
//
void CBB_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
int iSel = 0;
if (-1 != (iSel = CBB_HitTest(x, y)))
{
// Move command handling from LButtonUp to LButtonDown to avoid
// duplicate messages being sent from double clicks - Nash Bug #15450
if (0 <= iSel)
{
SendMessage(GetParent(hwnd), WM_COMMAND, m_rgButtons[iSel].id, (LPARAM) hwnd);
CBB_SetSelBtn(-1,hwnd);
}
}
return;
}
//
// FUNCTION: CButtonBar::OnMouseMove()
//
// PURPOSE: If the user is dragging the bar around, we need to determine
// which side of the parent window the mouse is closest to and
// move the button bar to that edge.
//
// If the user is not dragging, then we need to decide if the
// mouse is over a button and if so highlight the text.
//
void CBB_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
{
POINT pt = {x, y};
int iSel;
POINT ptScreen = {x, y};
// If we're not dragging the bar around, the just update the button
// selection.
iSel = CBB_HitTest(x, y);
CBB_SetSelBtn(iSel,hwnd);
if (iSel != -1)
SetCursor(LoadCursor(hinstMapiX, MAKEINTRESOURCE(idcurPointedHand)));
else
SetCursor(LoadCursor(NULL, IDC_ARROW));
CBB_DoHotTracking(hwnd);
return;
}
int CBB_OnMouseActivate(HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT msg)
{
return (MA_ACTIVATE);
}
//
// FUNCTION: CButtonBar::ConfigureRects()
//
// PURPOSE: Calculates the rectangles that are necessary for displaying
// the button bar based on the side of the parent window the
// bar is currently attached to.
//
void CBB_ConfigureRects(HWND hwnd)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
// Need to gather some font information first. We need the height of the
// folder title font all the time and we need the width of the longest
// button title if we're displayed horizontally.
HDC hdc;
int i;
int cxMaxTitle;
SIZE sizeString;
SIZE sizeRect;
int cyIconTitle;
int cxCenter;
int cyCenter;
TEXTMETRIC tmTitle;
hdc = GetDC(hwnd);
SelectObject(hdc, m_hfButton);
GetTextMetrics(hdc, &tmTitle);
// Button text width
cxMaxTitle = 0;
for (i = 0; i < m_cButtons; i++)
{
GetTextExtentPoint32(hdc, m_rgButtons[i].szTitle,
lstrlen(m_rgButtons[i].szTitle),
&sizeString);
if (sizeString.cx > cxMaxTitle)
cxMaxTitle = sizeString.cx;
}
// Add a little buffer here just to make it look nice.
cxMaxTitle += 10;
ReleaseDC(hwnd, hdc);
// Now calculate the button rectangles. Each button will have three rects
// associated with it. The first rectangle is the overall bounding rect
// which contains the image and title. The next rectangle is the rect for
// the image which is centered horizontally within the bounding rect and
// vertically when combined with the title. The final rect is the title.
// Calculate the initial bounding rectangle based on whether or not we're
// horizontal or vertical. sizeRect is the dimensions of each button's
// bounding rectangle.
{
RECT rcBound,rcWnd;
int cyButton=0,cxButton=0;
ImageList_GetIconSize(m_himlButtons, &cxButton, &cyButton);
GetClientRect(hwnd,&rcWnd);
sizeRect.cx = cxMaxTitle;
sizeRect.cy = rcWnd.bottom - rcWnd.top;
SetRect(&rcBound, 0, 0, sizeRect.cx, sizeRect.cy);
// Also calculate the offsets needed to center the image and text within
// the bound.
cyIconTitle = tmTitle.tmHeight + cyButton;
cxCenter = ((rcBound.right - rcBound.left) - cxButton) / 2;
cyCenter = ((rcBound.bottom - rcBound.top) - cyIconTitle) / 2;
// Now loop through all the buttons
for (i = 0; i < m_cButtons; i++)
{
m_rgButtons[i].rcBound = rcBound;
// Center the image horizontally within the bounding rect.
m_rgButtons[i].rcIcon.left = m_rgButtons[i].rcBound.left + cxCenter;
m_rgButtons[i].rcIcon.top = m_rgButtons[i].rcBound.top + cyCenter;
m_rgButtons[i].rcIcon.right = m_rgButtons[i].rcIcon.left + cxButton;
m_rgButtons[i].rcIcon.bottom = m_rgButtons[i].rcIcon.top + cyButton;
// And the button title below the image
m_rgButtons[i].rcTitle.left = m_rgButtons[i].rcBound.left + 1;
m_rgButtons[i].rcTitle.top = m_rgButtons[i].rcIcon.bottom;
m_rgButtons[i].rcTitle.right = m_rgButtons[i].rcBound.right - 1;
m_rgButtons[i].rcTitle.bottom = m_rgButtons[i].rcTitle.top + (tmTitle.tmHeight);// * 2);
// Offset the rcBound to the next button.
OffsetRect(&rcBound, sizeRect.cx, 0);
}
}
}
//
// FUNCTION: CButtonBar::OnTimer()
//
// PURPOSE: When the timer fires we check to see if the mouse is still
// over the button bar window. If not we remove the selection
// from the active button.
//
void CBB_OnTimer(HWND hwnd, UINT id)
{
POINT pt;
GetCursorPos(&pt);
if (hwnd != WindowFromPoint(pt))
{
CBB_SetSelBtn(-1,hwnd);
}
CBB_EndHotTracking(hwnd);
}
//
// FUNCTION: CButtonBar::DoHotTracking()
//
// PURPOSE: Starts a timer that allows the button bar to track the mouse
// in case it leaves the button bar window.
//
void CBB_DoHotTracking(HWND hwnd)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
CBB_EndHotTracking(hwnd);
m_fHotTrackTimer = SetTimer(hwnd, idtTrack, HOTTRACK_TIMER, NULL);
}
//
// FUNCTION: CButtonBar::EndHotTracking()
//
// PURPOSE: If the timer was set to track the mouse, we kill it and reset
// our state.
//
void CBB_EndHotTracking(HWND hwnd)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if (m_fHotTrackTimer)
{
KillTimer(hwnd, idtTrack);
m_fHotTrackTimer = FALSE;
}
}
//
// FUNCTION: CButtonBar::HitTest()
//
// PURPOSE: Returns the button number that the passed in position is
// over. If the mouse is over the menu button, it returns
// -2. Otherwise, if the mouse is not over a button the function
// returns -1.
//
// PARAMETERS:
// x, y - Position in client coordinates to check.
//
int CBB_HitTest(int x, int y)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
POINT pt = {x, y};
int i;
// Walk through the different buttons and determine if the point is
// within either their image or title.
for (i = 0; i < m_cButtons; i++)
{
if (PtInRect(&m_rgButtons[i].rcBound, pt))
/* PtInRect(&m_rgButtons[i].rcIcon, pt) ||
PtInRect(&m_rgButtons[i].rcTitle, pt)) */
{
return (i);
}
}
// If we're not over a button then return a default value.
return (-1);
}
//
// FUNCTION: CButtonBar::CBB_SetSelBtn()
//
// PURPOSE: Changes the button selection to the specified button.
//
void CBB_SetSelBtn(int iSel,HWND hwnd)
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if (m_iSelect != iSel)
{
HDC hdc = GetDC(hwnd);
// Remove the old selection
if (m_iSelect >= 0)
InvalidateRect(hwnd, &m_rgButtons[m_iSelect].rcTitle, FALSE);
// Add the new selection
if (iSel >= 0)
InvalidateRect(hwnd, &m_rgButtons[iSel].rcTitle, FALSE);
m_iOldSelect = m_iSelect;
// if (m_iOldSelect >= 0)
// DrawFocusRect(hdc, &m_rgButtons[m_iOldSelect].rcBound);
m_iSelect = iSel;
// if (m_iSelect >= 0)
// DrawFocusRect(hdc, &m_rgButtons[m_iSelect].rcBound);
ReleaseDC(hwnd, hdc);
}
return;
}