📄 caption.cpp
字号:
//////////////////////////////////////////////////////////////////// class RxCaption//// Generic caption painter. Handles WM_NCPAINT, WM_NCACTIVATE, etc. to// handle drawing custom captions. To use it://// - call Install from your frame's OnCreate function. // - Set a custom CaptionBackground if desired// - Set custom TextAttributes if required//// Derive from this class for custom caption layouts.// // If you are drawing custom caption buttons, you must handle WM_NCLBUTTONDOWN & co.// yourself. CCaption does not handle the mouse for custom caption buttons. //// Author: Dave Lorde (dlorde@cix.compulink.co.uk)//// Copyright 1999//// - based on a 1997 Microsoft Systems Journal// C++ Q&A article by Paul DiLascia. ////////////////////////////////////////////////////////////////////#include "StdAfx.h"#include "Caption.h"#include "SuppressStyle.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endifIMPLEMENT_DYNAMIC(RxCaption, RxSubclassWnd);////////// Default Constructor //RxCaption::RxCaption(){ m_crMask = RGB(255, 0, 0); m_crActive = RGB(132,126,125); m_crInactive = RGB( 62, 56, 55); m_crActiveText = -1; m_crInactiveText = -1; Invalidate();}RxCaption::~RxCaption(){}//////////////////// Install caption handler. //BOOL RxCaption::Install(CFrameWnd* pFrameWnd){ ASSERT_KINDOF(CFrameWnd, pFrameWnd); return HookWindow(pFrameWnd);}/////////////////// Regenerate and display caption//void RxCaption::Refresh(){ Invalidate(); PaintCaption();}//////////////////// Ensure caption bitmaps are repainted next time through OnNcPaint()//void RxCaption::Invalidate() { m_szCaption = CSize(0,0); }//////////////////// Message handler handles caption-related messages//LRESULT RxCaption::WindowProc(UINT msg, WPARAM wp, LPARAM lp){ switch (msg) { case WM_NCPAINT: OnNcPaint(HRGN(wp)); return 0; case WM_NCACTIVATE: return OnNcActivate(wp); case WM_SETTEXT: OnSetText((LPCTSTR)lp); return 0; case WM_SYSCOLORCHANGE: case WM_SETTINGCHANGE: OnColorChange(); return 0; } // We don't handle it: pass along return RxSubclassWnd::WindowProc(msg, wp, lp);}/////////////////// Handle WM_NCPAINT for main window//void RxCaption::OnNcPaint(HRGN hRgn){ ASSERT_VALID(m_pWndHooked); CWnd& wnd = *m_pWndHooked; CRect rcCaption = GetCaptionRect(); // caption rectangle in window coords CRect rcWindow; CRect rcButton; wnd.GetWindowRect(&rcWindow); // .. get window rect rcCaption += rcWindow.TopLeft(); // convert caption rect to screen coords // Don't bother painting if the caption doesn't lie within the region. // if ((WORD)hRgn > 1 && !::RectInRegion(hRgn, &rcCaption)) { Default(); // just do default thing return; // and quit } DWORD dwStyle = wnd.GetStyle(); // Exclude caption from update region // HRGN hRgnCaption = ::CreateRectRgnIndirect(&rcCaption); HRGN hRgnNew = ::CreateRectRgnIndirect(&rcCaption); HRGN hRgnButton; // wParam is not a valid region: create one that's the whole // window minus the caption bar // HRGN hRgnAll = ::CreateRectRgnIndirect(&rcWindow); CombineRgn(hRgnNew, hRgnAll, hRgnCaption, RGN_DIFF); DeleteObject(hRgnAll); int cxIcon = GetSystemMetrics(SM_CXSIZE); int cyIcon = GetSystemMetrics(SM_CYSIZE); if(cxIcon >= 25) { // window XP style if(dwStyle & WS_SYSMENU) { rcButton.left = rcCaption.left; rcButton.top = rcCaption.top; rcButton.right = rcButton.left + cxIcon; rcButton.bottom = rcButton.top + cyIcon; rcButton.DeflateRect(2, 1, 0, 1); hRgnButton = ::CreateRectRgnIndirect(&rcButton); CombineRgn(hRgnNew, hRgnNew, hRgnButton, RGN_OR); DeleteObject(hRgnButton); ////////////// // Close box has a 2 pixel border on all sides but left, which is zero // rcButton.left = rcCaption.left + (rcCaption.Width() - (cxIcon-2)); rcButton.top = rcCaption.top; rcButton.right = rcButton.left + (cxIcon-4); rcButton.bottom = rcButton.top + cyIcon; rcButton.DeflateRect(0, 2, 0, 2); hRgnButton = ::CreateRectRgnIndirect(&rcButton); CombineRgn(hRgnNew, hRgnNew, hRgnButton, RGN_OR); DeleteObject(hRgnButton); } ////////////// // Max/restore button is like close box; just shift rectangle left // Also does help button, if any. // if((dwStyle & WS_MAXIMIZEBOX) || (wnd.GetExStyle() & WS_EX_CONTEXTHELP)) { rcButton.left = rcCaption.left + (rcCaption.Width() - (cxIcon-2)*2); rcButton.top = rcCaption.top; rcButton.right = rcButton.left + (cxIcon-4); rcButton.bottom = rcButton.top + cyIcon; rcButton.DeflateRect(0, 2, 0, 2); hRgnButton = ::CreateRectRgnIndirect(&rcButton); CombineRgn(hRgnNew, hRgnNew, hRgnButton, RGN_OR); DeleteObject(hRgnButton); } /////////////// // Minimize button has 2 pixel border on all sides but right. // if (dwStyle & WS_MINIMIZEBOX) { rcButton.left = rcCaption.left + (rcCaption.Width() - (cxIcon-2)*3); rcButton.top = rcCaption.top; rcButton.right = rcButton.left + (cxIcon-4); rcButton.bottom = rcButton.top + cyIcon; rcButton.DeflateRect(0, 2, 0, 2); hRgnButton = ::CreateRectRgnIndirect(&rcButton); CombineRgn(hRgnNew, hRgnNew, hRgnButton, RGN_OR); DeleteObject(hRgnButton); } } else { ////////////// // Within the basic button rectangle, Windows 95 uses a 1 or 2 pixel border // Icon has 2 pixel border on left, 1 pixel on top/bottom, 0 right // if(dwStyle & WS_SYSMENU) { rcButton.left = rcCaption.left; rcButton.top = rcCaption.top; rcButton.right = rcButton.left + cxIcon; rcButton.bottom = rcButton.top + cyIcon; rcButton.DeflateRect(2, 1, 0, 1); hRgnButton = ::CreateRectRgnIndirect(&rcButton); CombineRgn(hRgnNew, hRgnNew, hRgnButton, RGN_OR); DeleteObject(hRgnButton); ////////////// // Close box has a 2 pixel border on all sides but left, which is zero // rcButton.left = rcCaption.left + (rcCaption.Width() - cxIcon); rcButton.top = rcCaption.top; rcButton.right = rcButton.left + cxIcon; rcButton.bottom = rcButton.top + cyIcon; rcButton.DeflateRect(0, 2, 2, 2); hRgnButton = ::CreateRectRgnIndirect(&rcButton); CombineRgn(hRgnNew, hRgnNew, hRgnButton, RGN_OR); DeleteObject(hRgnButton); } ////////////// // Max/restore button is like close box; just shift rectangle left // Also does help button, if any. // if((dwStyle & WS_MAXIMIZEBOX) || (wnd.GetExStyle() & WS_EX_CONTEXTHELP)) { rcButton.left = rcCaption.left + (rcCaption.Width() - cxIcon*2); rcButton.top = rcCaption.top; rcButton.right = rcButton.left + cxIcon; rcButton.bottom = rcButton.top + cyIcon; rcButton.DeflateRect(0, 2, 2, 2); hRgnButton = ::CreateRectRgnIndirect(&rcButton); CombineRgn(hRgnNew, hRgnNew, hRgnButton, RGN_OR); DeleteObject(hRgnButton); } /////////////// // Minimize button has 2 pixel border on all sides but right. // if (dwStyle & WS_MINIMIZEBOX) { rcButton.left = rcCaption.left + (rcCaption.Width() - cxIcon*3); rcButton.top = rcCaption.top; rcButton.right = rcButton.left + cxIcon; rcButton.bottom = rcButton.top + cyIcon; rcButton.DeflateRect(2, 2, 0, 2); hRgnButton = ::CreateRectRgnIndirect(&rcButton); CombineRgn(hRgnNew, hRgnNew, hRgnButton, RGN_OR); DeleteObject(hRgnButton); } } // Call Windows to do WM_NCPAINT with altered update region // MSG& msg = AfxGetThreadState()->m_lastSentMsg; WPARAM savewp = msg.wParam; // save original wParam msg.wParam = (WPARAM)hRgnNew; // set new region for DefWindowProc Default(); // Normal message handling DeleteObject(hRgnCaption); // clean up DeleteObject(hRgnNew); // ... msg.wParam = savewp; // restore original wParam PaintCaption(); // Now paint our special caption}//////////////////// Handle WM_NCACTIVATE for main window//BOOL RxCaption::OnNcActivate(BOOL bActive){ ASSERT_VALID(m_pWndHooked); CFrameWnd& frame = *((CFrameWnd*)m_pWndHooked); ASSERT_KINDOF(CFrameWnd, &frame); // Mimic MFC kludge to stay active if WF_STAYACTIVE bit is on // if (frame.m_nFlags & WF_STAYACTIVE) bActive = TRUE; if (!frame.IsWindowEnabled()) // but not if disabled bActive = FALSE; if (bActive == m_bActive) return TRUE; // nothing to do // In case this is a MDI app, manually activate/paint active MDI child // window, because Windows won't do it if parent frame is invisible. // Must do this BEFORE calling Default, or it will not work. // CFrameWnd* pActiveFrame = frame.GetActiveFrame(); if (pActiveFrame != &frame) { pActiveFrame->SendMessage(WM_NCACTIVATE, bActive); pActiveFrame->SendMessage(WM_NCPAINT); } // Turn WS_VISIBLE off before calling DefWindowProc, // so DefWindowProc won't paint and thereby cause flicker. // { RxSuppressStyle ss(frame.GetSafeHwnd(), WS_VISIBLE); MSG& msg = AfxGetThreadState()->m_lastSentMsg; msg.wParam = bActive; Default(); // Normal message handling } // At this point, nothing has happened (since WS_VISIBLE was off). // Now it's time to paint. // m_bActive = bActive; // update state frame.SendMessage(WM_NCPAINT); // paint non-client area (frame too) return TRUE; // done OK}//////////////////// Handle WM_SETTEXT for main window//void RxCaption::OnSetText(LPCTSTR){ ASSERT_VALID(m_pWndHooked); CWnd& wnd = *m_pWndHooked; // Turn WS_VISIBLE style off before calling Windows to // set the text. Reset to visible afterwards {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -