// CoolButton.cpp : implementation file // #include "stdafx.h" #include "p4win.h" #include "CoolBtn.h" #if _MFC_VER >= 0x0700 #define USE_THEMES #include <uxtheme.h> #endif #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif const int nDropBtnWidth = 16; ///////////////////////////////////////////////////////////////////////////// // CCoolButton // ======== // // To Use: // 1. In the RC file, create the button as BS_OWNERDRAW. // Optionally, create a Bitmap resource 16x15 Pixels // - normal default size for a toolbar bitmap. // // 2. in the header for the dialog class: // #include "CoolBtn.h" // then create the necessary button widgets in the //{{AFX_DATA() section: // CCoolButton m_DblBtn; // // 3. In the InitDialog() for the dialog: // // a) Optionally, Call SetButtonImage specificing the // Transparency color reference. // (Usally RGB(255, 0, 255) magenta) // m_DblBtn.SetButtonImage(IDC_BTNIMAGE, RGB(255,0,255)); // // b) Either call CCoolButton's SetIDs function: // m_DblBtn.SetIDs(IDC_BTNPUSH, IDC_BTNMENU); // the first ID must be the same as the ID in the RC file! // --or-- // Add menu item(s) to the button: // m_DblBtn.AddMenuItem(nMenuId1, strMenu1, nMenuFlags1); // m_DblBtn.AddMenuItem(nMenuId2, strMenu2, nMenuFlags2); // // If you do both SetIDs() and AddMenuItem()s, only the AddMenuItem // will be called and the second ID will be ignored. // // c) Optionally, call CCoolButton's show split function: // m_DblBtn.SetSplit(bSplit); // The default is to show the split (TRUE). If set to FALSE, only // the AddMenuItem()s or 2nd ID in SetIDs() will be called and the // base id (1st ID in SetIDs()==ID in RC file) will be ignored. // // d) Optionally call m_DblBtn.SetAsDefaultBtn(TRUE) to make the button // the default button. // // 4. Add the appropiate ON_COMMAND handlers in the parent windows message map // // 5. You can also call SetIDs() or SetSplit() later to dynamically change the // button and you can later add more AddMenuItem(). //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: CCoolButton // // DESCRIPTION: // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin as CCoolBtn // L Brasington 03/06/06 2.0 Rewritten as CCoolButton // //////////////////////////////////////////////////////////////////////////////// CCoolButton::CCoolButton() { m_nID2 = 0; m_bPushed = FALSE; m_bLoaded = FALSE; m_bMenuPushed = FALSE; m_bMenuLoaded = FALSE; m_bDefaultBtn = m_bActAsDefaultBtn = FALSE; m_bSplit = TRUE; m_bOverControl = FALSE; m_bTracking = FALSE; ZeroMemory(&m_bm, sizeof m_bm); m_menu.CreatePopupMenu(); m_themeLib = LoadLibrary(_T("UxTheme.dll")); } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: ~CCoolButton // // DESCRIPTION: // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // //////////////////////////////////////////////////////////////////////////////// CCoolButton::~CCoolButton() { if(m_themeLib) FreeLibrary(m_themeLib); } BEGIN_MESSAGE_MAP(CCoolButton, CButton) //{{AFX_MSG_MAP(CCoolButton) ON_WM_KEYDOWN() ON_WM_SYSKEYDOWN() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_WM_SYSCOLORCHANGE() ON_WM_GETDLGCODE() //}}AFX_MSG_MAP ON_MESSAGE(BM_SETSTYLE, OnSetStyle) ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover ) ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave ) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CCoolButton message handlers //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: SetIDs // // DESCRIPTION: Set the IDs // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // L Brasington 03/06/06 2.0 Rewritten as CCoolButton // //////////////////////////////////////////////////////////////////////////////// BOOL CCoolButton::SetIDs( UINT nID1, UINT nID2 ) { m_nID1 = nID1; m_nID2 = nID2; return TRUE; } //////////////////////////////////////////////////////////////////////////////// UINT CCoolButton::OnGetDlgCode() { UINT nCode = CButton::OnGetDlgCode(); nCode |= (m_bActAsDefaultBtn ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON); return nCode; } // mask for control's type #undef BS_TYPEMASK #define BS_TYPEMASK SS_TYPEMASK LRESULT CCoolButton::OnSetStyle(WPARAM wParam, LPARAM lParam) { m_bActAsDefaultBtn = wParam & BS_DEFPUSHBUTTON; // can't change control type after owner-draw is set. // let the system process changes to other style bits // and redrawing, while keeping owner-draw style return DefWindowProc(BM_SETSTYLE, (wParam & ~BS_TYPEMASK) | BS_OWNERDRAW, lParam); } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: DrawItem // // DESCRIPTION: Called in response to draw the button // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // L Brasington 03/06/06 2.0 Rewritten as CCoolButton, Added XP support // //////////////////////////////////////////////////////////////////////////////// #ifdef USE_THEMES typedef HTHEME(__stdcall *PFNOPENTHEMEDATA)(HWND hwnd, LPCWSTR pszClassList); typedef HRESULT(__stdcall *PFNCLOSETHEMEDATA)(HTHEME hTheme); typedef HRESULT(__stdcall *PFNDRAWTHEMEBACKGROUND)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect); typedef HRESULT(__stdcall *PFNGETTHEMEBACKGROUNDCONTENTRECT)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, RECT *pContentRect); #endif void CCoolButton::DrawItem(DRAWITEMSTRUCT* lpDIS) { if (lpDIS->CtlType != ODT_BUTTON) return; CFont *pFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT)); CDC dcMem; CBitmap bmp; CRect btnRect(lpDIS->rcItem); CRect trueRect(btnRect); CRect rectFocus(btnRect); CDC *pDC = CDC::FromHandle(lpDIS->hDC); BOOL bDisabled = ODS_DISABLED & lpDIS->itemState; #ifdef USE_THEMES HTHEME hTheme = 0; if(m_themeLib) { PFNOPENTHEMEDATA pOpenThemeData = (PFNOPENTHEMEDATA) GetProcAddress(m_themeLib, "OpenThemeData"); if(pOpenThemeData) hTheme = (pOpenThemeData)(m_hWnd, L"Button"); } if(hTheme) { // attempt to map owner draw states to theme pushbutton states int iState = PBS_NORMAL; if(m_bOverControl)//lpDIS->itemState & ODS_HOTLIGHT) iState = PBS_HOT; else if(m_bDefaultBtn || m_bActAsDefaultBtn)//lpDIS->itemState & ODS_DEFAULT) iState = PBS_DEFAULTED; else if(lpDIS->itemState & ODS_SELECTED) iState = PBS_PRESSED; HRESULT hr; HDC hDC = lpDIS->hDC; RECT rc = lpDIS->rcItem; // let theme draw background PFNDRAWTHEMEBACKGROUND pDrawThemeBackground = (PFNDRAWTHEMEBACKGROUND) GetProcAddress(m_themeLib, "DrawThemeBackground"); if(!pDrawThemeBackground) return; hr = (pDrawThemeBackground)(hTheme, hDC, BP_PUSHBUTTON, iState, &rc, 0); if(hr != S_OK) return; // get rect to put content in RECT rcContent; PFNGETTHEMEBACKGROUNDCONTENTRECT pGetThemeBackgroundContentRect = (PFNGETTHEMEBACKGROUNDCONTENTRECT) GetProcAddress(m_themeLib, "GetThemeBackgroundContentRect"); if(!pGetThemeBackgroundContentRect) return; hr = (pGetThemeBackgroundContentRect)(hTheme, hDC, BP_PUSHBUTTON, iState, &rc, &rcContent); if(hr != S_OK) return; rectFocus = rcContent; if (!m_bMenuPushed) rectFocus.OffsetRect(m_bPushed,m_bPushed); if (m_bSplit) rectFocus.right -= nDropBtnWidth; if (lpDIS->itemState & ODS_FOCUS || m_bPushed) { if (!m_bMenuPushed) ::DrawFocusRect(lpDIS->hDC, &rcContent); } } else #endif { //////////////////////////////////////// // Button Background // //////////////////////////////////////// CBrush brush(GetSysColor(COLOR_BTNFACE)); pDC->FillRect(trueRect,&brush); if (m_bDefaultBtn) btnRect.DeflateRect(1,1); rectFocus.DeflateRect(4,4); if (!m_bMenuPushed) rectFocus.OffsetRect(m_bPushed,m_bPushed); if (m_bSplit) rectFocus.right -= nDropBtnWidth; //////////////////////////////////////// // Button in a normal state // //////////////////////////////////////// if (!m_bPushed || m_bMenuPushed) pDC->DrawFrameControl(&btnRect,DFC_BUTTON,DFCS_BUTTONPUSH); //////////////////////////////////////// // Default Button State // //////////////////////////////////////// if ((m_bDefaultBtn || m_bPushed) && !bDisabled) { pDC->FrameRect(&lpDIS->rcItem,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH))); if (m_bPushed && !m_bMenuPushed) pDC->FrameRect(&btnRect,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH))); } //////////////////////////////////////// // State Focus // //////////////////////////////////////// if (lpDIS->itemState & ODS_FOCUS || m_bPushed) { pDC->FrameRect(&lpDIS->rcItem,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH))); if (!m_bMenuPushed) pDC->DrawFocusRect(&rectFocus); } //////////////////////////////////////// // Action Focus // //////////////////////////////////////// if ((lpDIS->itemAction & ODA_FOCUS)) if (!m_bMenuPushed) pDC->DrawFocusRect(&rectFocus); } //////////////////////////////////////// // Draw out bitmap // //////////////////////////////////////// // Draw out bitmap if (m_bLoaded) { if (!bDisabled) { m_IL.DrawIndirect(pDC,0,CPoint(6+m_bPushed,6+m_bPushed), CSize(m_bm.bmWidth, m_bm.bmHeight), CPoint(0,0),ILD_NORMAL); } else { pDC->DrawState(CPoint(6+m_bPushed,6+m_bPushed), CSize(m_bm.bmWidth, m_bm.bmHeight), m_hbmpDisabled, DST_BITMAP | DSS_DISABLED); } } //////////////////////////////////////// // Draw out text // //////////////////////////////////////// pDC->SelectObject(pFont); CRect rectText(rectFocus); if (!m_bSplit) rectText.right -= nDropBtnWidth; rectText.left += m_bm.bmWidth + 2; CString strCaption; GetWindowText(strCaption); pDC->SetBkMode(TRANSPARENT); pDC->SetBkColor(GetSysColor(COLOR_BTNFACE)); if (ODS_DISABLED & lpDIS->itemState) { rectText.OffsetRect(1,1); pDC->SetTextColor(GetSysColor(COLOR_WINDOW)); pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER); rectText.OffsetRect(-1,-1); pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT)); pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER); } else { pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER); } CRect rectSplit(btnRect); rectSplit.DeflateRect(2,2); rectSplit.right -= nDropBtnWidth; //////////////////////////////////////// // Drop down split // //////////////////////////////////////// if (m_bSplit) { CPen brFace(PS_SOLID,1,GetSysColor(COLOR_3DSHADOW)); pDC->SelectObject(&brFace); pDC->MoveTo(rectSplit.right, rectSplit.top); pDC->LineTo(rectSplit.right, rectSplit.bottom); CPen brLite(PS_SOLID,1,GetSysColor(COLOR_3DHILIGHT)); pDC->SelectObject(&brLite); pDC->MoveTo(rectSplit.right+1 , rectSplit.top); pDC->LineTo(rectSplit.right+1, rectSplit.bottom); } //////////////////////////////////////// // Draw Arrow // //////////////////////////////////////// rectSplit.left = rectSplit.right; rectSplit.right += nDropBtnWidth; CPoint pt(rectSplit.CenterPoint()); pt += CPoint(m_bPushed,m_bPushed); CPen penBlack(PS_SOLID, 1, bDisabled ? GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_WINDOWTEXT)); pDC->SelectObject(&penBlack); DrawArrow(pDC,pt); //////////////////////////////////////// // Drop down state // //////////////////////////////////////// if (m_bMenuPushed && !bDisabled) { rectSplit.InflateRect(1,1); pDC->DrawEdge(rectSplit,BDR_SUNKENOUTER, BF_RECT); } if(hTheme) { PFNCLOSETHEMEDATA pCloseThemeData = (PFNCLOSETHEMEDATA)GetProcAddress(m_themeLib, "CloseThemeData"); if(!pCloseThemeData) return; (pCloseThemeData)(hTheme); } } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: DrawArrow // // DESCRIPTION: Draws drop down arrow, we could use DrawFrameControl - a bit too // messy // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // //////////////////////////////////////////////////////////////////////////////// void CCoolButton::DrawArrow(CDC* pDC,CPoint ArrowTip) { CPoint ptDest; pDC->SetPixel(ArrowTip,RGB(0,0,0)); ArrowTip -= CPoint(1,1); pDC->MoveTo(ArrowTip); ptDest = ArrowTip; ptDest += CPoint(3,0); pDC->LineTo(ptDest); ArrowTip -= CPoint(1,1); pDC->MoveTo(ArrowTip); ptDest = ArrowTip; ptDest += CPoint(5,0); pDC->LineTo(ptDest); ArrowTip -= CPoint(1,1); pDC->MoveTo(ArrowTip); ptDest = ArrowTip; ptDest += CPoint(7,0); pDC->LineTo(ptDest); } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: OnLButtonDown // // DESCRIPTION: handles button pressed state, including drop down menu // // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // L Brasington 03/06/06 2.0 Rewritten as CCoolButton // //////////////////////////////////////////////////////////////////////////////// void CCoolButton::OnLButtonDown(UINT nFlags, CPoint point) { SetFocus(); if (m_bMenuPushed) { m_bMenuPushed = FALSE; Invalidate(); return; } if (!m_bSplit || HitMenuBtn(point)) { OnMenuBtn(); return; } m_bPushed = TRUE; Invalidate(); CButton::OnLButtonDown(nFlags, point); } BOOL CCoolButton::OnMenuBtn() { if (!m_bMenuLoaded) { if (m_nID2) { GetParent()->PostMessage(WM_COMMAND, m_nID2, 0); m_bMenuPushed = TRUE; Invalidate(); return TRUE; } } else { m_bMenuPushed = TRUE; Invalidate(); CRect rc; GetWindowRect(rc); int x = rc.left; int y = rc.bottom; m_menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON,x,y,GetParent()); m_bMenuPushed = FALSE; Invalidate(); return TRUE; } return FALSE; } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: OnLButtonUp // // DESCRIPTION: Redraws button in normal state // // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // L Brasington 03/06/06 2.0 Rewritten as CCoolButton // //////////////////////////////////////////////////////////////////////////////// void CCoolButton::ClearButtonPushed() { if (m_bPushed) { m_bPushed = FALSE; Invalidate(); } if (m_bMenuPushed) { m_bMenuPushed = FALSE; Invalidate(); } } void CCoolButton::OnLButtonUp(UINT nFlags, CPoint point) { ClearButtonPushed(); CButton::OnLButtonUp(nFlags, point); } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: OnMouseMove // // DESCRIPTION: Tracks mouse whilst pressed // // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // L Brasington 03/06/06 2.0 Rewritten as CCoolButton // //////////////////////////////////////////////////////////////////////////////// LRESULT CCoolButton::OnMouseHover(WPARAM wparam, LPARAM lparam) { m_bOverControl=TRUE; Invalidate(); return 1; } LRESULT CCoolButton::OnMouseLeave(WPARAM wparam, LPARAM lparam) { m_bTracking = FALSE; m_bOverControl = FALSE; Invalidate(FALSE); return 0; } void CCoolButton::OnMouseMove(UINT nFlags, CPoint point) { if (m_bPushed) { ClientToScreen(&point); if (WindowFromPoint(point) != this) { m_bPushed = FALSE; Invalidate(); } } if (!m_bTracking) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.hwndTrack = m_hWnd; tme.dwFlags = TME_LEAVE|TME_HOVER; tme.dwHoverTime = 1; m_bTracking = _TrackMouseEvent(&tme) != FALSE; } CButton::OnMouseMove(nFlags, point); } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: SetButtonImage // // DESCRIPTION: Sets the button image, COLORREF crMask specifics the transparency // color // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // //////////////////////////////////////////////////////////////////////////////// BOOL CCoolButton::SetButtonImage(UINT nResourceId, COLORREF crMask) { // The ID must exist also as a bitmap resource!!! m_btnImage.LoadBitmap(nResourceId); m_btnImage.GetObject(sizeof m_bm, &m_bm); m_IL.Create( nResourceId, m_bm.bmWidth, 1, crMask ); m_bLoaded = TRUE; m_crMask = crMask; HBITMAP bmTemp; COLORMAP mapColor; mapColor.from = crMask; mapColor.to = RGB(255,255,255); bmTemp = (HBITMAP)::CreateMappedBitmap(AfxGetApp()->m_hInstance, nResourceId, IMAGE_BITMAP, &mapColor, 1); m_hbmpDisabled = (HBITMAP)::CopyImage(bmTemp, IMAGE_BITMAP, m_bm.bmWidth, m_bm.bmHeight, LR_COPYDELETEORG); return m_bLoaded; } void CCoolButton::OnSetFocus(CWnd* pOldWnd) { CButton::OnSetFocus(pOldWnd); Invalidate(); } void CCoolButton::OnKillFocus(CWnd* pNewWnd) { CButton::OnKillFocus(pNewWnd); } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: OnSysColorChange // // DESCRIPTION: Called when system colors change, force a button redraw // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // //////////////////////////////////////////////////////////////////////////////// void CCoolButton::OnSysColorChange() { CButton::OnSysColorChange(); Invalidate(); } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: HitMenuBtn // // DESCRIPTION: Helper function to test for menu button hit... // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // L Brasington 03/06/06 2.0 Rewritten as CCoolButton // //////////////////////////////////////////////////////////////////////////////// BOOL CCoolButton::HitMenuBtn(CPoint point) { if (!m_bMenuLoaded && !m_nID2) return FALSE; // Don't allow menu button drop down if no menu items are loaded ClientToScreen(&point); CRect rect; GetWindowRect(rect); rect.left = rect.right - nDropBtnWidth; return rect.PtInRect(point); } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: AddMenuItem // // DESCRIPTION: Adds a menu item and id to our menu. // // NOTES: // // MAINTENANCE: // Name: Date: Version: Notes: // NT ALMOND 210100 1.0 Origin // //////////////////////////////////////////////////////////////////////////////// BOOL CCoolButton::AddMenuItem(UINT nMenuId,const CString strMenu, UINT nMenuFlags) { BOOL bRet = m_menu.AppendMenu(nMenuFlags | MF_STRING, nMenuId, (LPCTSTR)strMenu); m_bMenuLoaded |= bRet; return bRet; } //////////////////////////////////////////////////////////////////////////////// void CCoolButton::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == 'F' && GetKeyState(VK_CONTROL) & 0x8000) // ^F == Find GetParent()->PostMessage(WM_COMMAND, ID_POSITIONTOPATTERN, 0); else if (nChar == VK_F3) GetParent()->PostMessage(WM_COMMAND, GetKeyState(VK_SHIFT) & 0x8000 ? ID_FINDPREV : ID_FINDNEXT, 0); else CButton::OnChar(nChar, nRepCnt, nFlags); } void CCoolButton::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { switch ( nChar ) { case VK_DOWN: OnMenuBtn(); break; } CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 16169 | perforce_software | Move files to follow new path scheme for branches. | ||
//guest/perforce_software/p4win/gui/CoolBtn.cpp | |||||
#1 | 8562 | Matt Attaway |
These feet never stop running. Initial commit of the P4Win source code. To the best of our knowledge this compiles and runs using the 2013.3 P4 API and VS 2010. Expect a few changes as we refine the build process. Please post any build issues to the forums. |