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
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;
|
|
}
|
|
|