DragonNest/Third/XTToolkitPro/Source/Controls/XTCaption.cpp

587 lines
13 KiB
C++
Raw Normal View History

2024-12-19 09:48:26 +08:00
// XTCaption.cpp : implementation of the CXTCaption class.
//
// This file is a part of the XTREME CONTROLS MFC class library.
// (c)1998-2008 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/XTPWinThemeWrapper.h"
#include "Common/XTPDrawHelpers.h"
#include "Resource.h"
#include "XTDefines.h"
#include "XTUtil.h"
#include "XTGlobal.h"
#include "XTButton.h"
#include "XTThemeManager.h"
#include "XTButtonTheme.h"
#include "XTCaptionTheme.h"
#include "XTCaption.h"
#include "XTCaptionPopupWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CXTCaptionButton
IMPLEMENT_THEME_HOST(CXTCaptionButton)
IMPLEMENT_THEME_REFRESH(CXTCaptionButton, CXTButton)
CXTCaptionButton::CXTCaptionButton()
: CXTButton(GetThemeFactoryClass())
, m_pCaption(NULL)
{
}
DWORD CXTCaptionButton::SetXButtonStyle(DWORD /*dwxStyle*/, BOOL bRedraw/*= TRUE*/)
{
DWORD dwOldStyle = m_dwxStyle;
CXTCaption* pCaption = DYNAMIC_DOWNCAST(CXTCaption, GetSafeHwnd() ? GetParent() : 0);
if (pCaption)
{
// set the button font and colors.
SetColorFace(pCaption->GetTheme()->m_clrFace);
SetColorText(pCaption->GetTheme()->m_clrText);
SetColorHilite(pCaption->GetTheme()->m_clrEdgeLight);
SetColorShadow(pCaption->GetTheme()->m_clrEdgeShadow);
// set the button font to match caption font.
SetFont(pCaption->GetFont());
// Redraw the button.
if (bRedraw)
Invalidate();
}
return dwOldStyle;
}
/////////////////////////////////////////////////////////////////////////////
// CXTCaption
IMPLEMENT_THEME_HOST(CXTCaption)
IMPLEMENT_THEME_REFRESH(CXTCaption, CStatic)
CXTCaption::CXTCaption()
: CXTThemeManagerStyleHost(GetThemeFactoryClass())
{
m_bAppCaption = false;
m_bUserColors = false;
m_strCaption = _T("");
m_hIcon = NULL;
m_pChildWnd = NULL;
m_pParentView = NULL;
m_pSplitterWnd = NULL;
m_pPopupWnd = NULL;
m_nOffset = 0;
m_nBorder = 0;
m_sizeIcon.cx = __min(XTAuxData().cxSmIcon, 16);
m_sizeIcon.cy = __min(XTAuxData().cySmIcon, 16);
m_dwExStyle = 0L;
}
CXTCaption::~CXTCaption()
{
}
IMPLEMENT_DYNAMIC(CXTCaption, CStatic)
BEGIN_MESSAGE_MAP(CXTCaption, CStatic)
//{{AFX_MSG_MAP(CXTCaption)
ON_WM_PAINT()
ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
ON_WM_ERASEBKGND()
ON_WM_WINDOWPOSCHANGED()
ON_WM_SYSCOLORCHANGE()
ON_WM_SIZE()
//}}AFX_MSG_MAP
ON_BN_CLICKED(XT_IDC_BTN_CLOSE, OnCaptButton)
ON_MESSAGE_VOID(CPWN_XT_PUSHPINBUTTON, OnPushPinButton)
ON_MESSAGE_VOID(CPWN_XT_PUSHPINCANCEL, OnPushPinCancel)
END_MESSAGE_MAP()
void CXTCaption::OnSize(UINT nType, int cx, int cy)
{
CStatic::OnSize(nType, cx, cy);
if (m_hIcon != NULL)
RedrawWindow();
}
void CXTCaption::OnPaint()
{
// background is already filled in gray
CPaintDC dc(this);
// Get the client rect.
CXTPClientRect rectClient(this);
// Paint to a memory device context to help
// eliminate screen flicker.
CXTPBufferDC memDC(dc);
// If the caption button is a valid window and visible exclude from painting...
if (::IsWindow(m_btnCaption.m_hWnd) && m_btnCaption.IsWindowVisible())
{
CXTPWindowRect rcButton(&m_btnCaption);
ScreenToClient(&rcButton);
memDC.ExcludeClipRect(&rcButton);
}
// draw the background, text and icon.
DrawCaptionBack(&memDC, rectClient);
DrawCaptionText(&memDC);
DrawCaptionIcon(&memDC, rectClient);
}
LRESULT CXTCaption::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
{
CDC* pDC = CDC::FromHandle((HDC)wParam);
if (pDC)
{
CXTPClientRect rectClient(this);
DrawCaptionBack(pDC, rectClient);
DrawCaptionText(pDC);
DrawCaptionIcon(pDC, rectClient);
}
return 1;
}
BOOL CXTCaption::OnEraseBkgnd(CDC* /*pDC*/)
{
return TRUE;
}
void CXTCaption::DrawCaptionBack(CDC* pDC, CRect& rcItem)
{
GetTheme()->DrawCaptionBack(pDC, this, rcItem);
}
void CXTCaption::DrawCaptionText(CDC* pDC)
{
GetTheme()->DrawCaptionText(pDC, this);
}
void CXTCaption::DrawCaptionIcon(CDC* pDC, CRect& rcItem)
{
GetTheme()->DrawCaptionIcon(pDC, this, rcItem);
}
BOOL CXTCaption::Create(CWnd* pParentWnd, LPCTSTR lpszWindowName, DWORD dwExStyle, DWORD dwStyle, const CRect& rect, UINT nID)
{
// Let the base class create the control.
if (!CStatic::Create(NULL, dwStyle | WS_CLIPCHILDREN, rect, pParentWnd, nID))
{
TRACE(_T("Unable to create caption.\n"));
return FALSE;
}
SetFont(&XTAuxData().font);
// save the style.
m_dwExStyle = (dwExStyle & (CPWS_EX_GROOVE_EDGE | CPWS_EX_RAISED_EDGE | CPWS_EX_CLOSEBUTTON));
ModifyStyleEx(0, (dwExStyle & ~m_dwExStyle));
// Save the window text.
m_strCaption = lpszWindowName;
if (HasCloseButton())
{
// Create the caption's close button.
if (!m_btnCaption.Create(NULL, WS_VISIBLE | WS_CHILD | BS_ICON | BS_OWNERDRAW | BS_CENTER | BS_VCENTER,
CRect(0, 0, 0, 0), this, XT_IDC_BTN_CLOSE))
{
TRACE0("Unable to create caption button.\n");
return -1;
}
// Create the image list used by frame buttons.
m_ilButton.Create (XT_IDB_BTN_OUT, 16, 1, RGB(255, 0, 255));
// and set the icon for the caption's close button
m_btnCaption.SetIcon(CSize(16, 15), m_ilButton.ExtractIcon(
(XTPColorManager()->GetCurrentSystemTheme() == xtpSystemThemeAero)? 3: 2));
}
else
{
// Create the button to be used with child window.
if (!m_btnCaption.Create(m_strCaption, BS_ICON | BS_OWNERDRAW | BS_VCENTER,
CRect(0, 0, 0, 0), this, XT_IDC_BTN_CLOSE))
{
TRACE0("Unable to create caption button.\n");
return FALSE;
}
m_bAppCaption = true;
}
m_btnCaption.SetCaption(this);
m_btnCaption.SetXButtonStyle(0, FALSE);
SetWindowPos(NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);
return TRUE;
}
void CXTCaption::ModifyCaptionStyle(int nBorderSize, CFont* pFont, LPCTSTR lpszWindText, HICON hIcon)
{
ASSERT(::IsWindow(m_hWnd));
if (nBorderSize != 0)
{
m_nBorder = nBorderSize;
}
if (pFont != NULL)
{
SetFont(pFont);
// button font should match caption
if (::IsWindow(m_btnCaption.m_hWnd))
m_btnCaption.SetFont(GetFont());
}
if (lpszWindText != NULL)
{
m_strCaption = lpszWindText;
}
if (hIcon != NULL)
{
m_hIcon = hIcon;
}
Invalidate();
}
void CXTCaption::SetChildWindow(CWnd* pChild, CWnd* pNotifyWnd)
{
ASSERT_VALID (pChild); // must be valid.
ASSERT_VALID (pNotifyWnd); // must be valid.
// save window pointers, and show caption button.
m_pChildWnd = pChild;
SetOwner(pNotifyWnd);
m_pParentView = pChild->GetParent();
ASSERT_KINDOF(CView, m_pParentView);
m_pSplitterWnd = m_pParentView->GetParent();
ASSERT_KINDOF(CSplitterWnd, m_pSplitterWnd);
// get the size of the child and parent windows.
m_pChildWnd->GetClientRect (&m_rcChild);
m_pParentView->GetClientRect (&m_rcParent);
m_pSplitterWnd->GetClientRect (&m_rcSplitter);
// save the size of the childs caption area.
m_nOffset = (m_rcParent.Height() - m_rcChild.Height());
// make the caption button visible.
m_btnCaption.ShowWindow(SW_SHOW);
m_btnCaption.UpdateWindow();
// inflate the size of the parent to add a border, this will
// also be the size of the popup window.
int cx = ::GetSystemMetrics (SM_CXEDGE)*2;
int cy = ::GetSystemMetrics (SM_CYEDGE)*2;
m_rcParent.InflateRect(cx, cy);
}
void CXTCaption::KillChildWindow()
{
// Hide the caption button.
if (::IsWindow(m_btnCaption.m_hWnd))
{
m_btnCaption.ShowWindow(SW_HIDE);
m_btnCaption.SetState(FALSE);
}
// Destroy the pop-up window.
if (::IsWindow(m_pPopupWnd->GetSafeHwnd()))
{
m_pPopupWnd->DestroyWindow();
}
SAFE_DELETE(m_pPopupWnd);
}
BOOL CXTCaption::ShowPopupWindow()
{
// already visible return TRUE.
if (::IsWindowVisible(m_pPopupWnd->GetSafeHwnd()))
return TRUE;
// if not a window yet create it.
if (!::IsWindow(m_pPopupWnd->GetSafeHwnd()))
{
m_pPopupWnd = new CXTCaptionPopupWnd;
if (!m_pPopupWnd->Create(CRect(0, 0, 0, 0), this, m_pChildWnd))
{
SAFE_DELETE(m_pPopupWnd);
return FALSE;
}
}
// view pointer is not valid.
if (!::IsWindow(m_pParentView->GetSafeHwnd()))
return FALSE;
// splitter pointer is not valid.
if (!::IsWindow(m_pSplitterWnd->GetSafeHwnd()))
return FALSE;
CRect rcPopup(m_rcParent);
m_pParentView->ClientToScreen(&rcPopup);
// get the current size of the splitter window.
CRect rcSplitter;
m_pSplitterWnd->GetClientRect(&rcSplitter);
// check to see if the size has changed.
if (rcSplitter.Height() > m_rcSplitter.Height())
{
rcPopup.bottom += (rcSplitter.Height() - m_rcSplitter.Height());
}
else if (m_rcSplitter.Height() > rcSplitter.Height())
{
rcPopup.bottom -= (m_rcSplitter.Height() - rcSplitter.Height());
}
// display the popup window.
m_pPopupWnd->MoveWindow(&rcPopup);
m_pPopupWnd->ShowWindow(SW_SHOW);
m_pPopupWnd->RecalcLayout();
// press the caption button.
m_btnCaption.SetState(TRUE);
return TRUE;
}
void CXTCaption::OnCaptButton()
{
if (HasCloseButton())
{
CWnd* pOwner = GetOwner();
ASSERT_VALID(pOwner);
if (pOwner)
{
// Notify of selection change.
pOwner->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(),
BN_CLICKED), (LPARAM)m_hWnd);
}
}
else
{
ShowPopupWindow();
}
}
void CXTCaption::OnPushPinButton()
{
KillChildWindow();
// get the current size of the child's parent window and
// adjust the size of the child accordingly.
m_pParentView->GetClientRect (&m_rcParent);
m_rcChild = m_rcParent;
m_rcChild.top += m_nOffset;
// move the child window to its correct location.
m_pChildWnd->MoveWindow (m_rcChild);
CWnd* pNotifyWnd = GetOwner();
ASSERT_VALID(pNotifyWnd);
if (::IsWindow(pNotifyWnd->GetSafeHwnd()))
{
// Notify that push pin button was pressed.
pNotifyWnd->SendMessage(CPWN_XT_PUSHPINBUTTON);
Invalidate();
}
}
void CXTCaption::OnPushPinCancel()
{
m_btnCaption.SetState(FALSE);
m_pPopupWnd->DestroyWindow();
SAFE_DELETE (m_pPopupWnd);
CWnd* pNotifyWnd = GetOwner();
ASSERT_VALID(pNotifyWnd);
if (::IsWindow(pNotifyWnd->GetSafeHwnd()))
{
// Notify that popup window has lost input focus.
pNotifyWnd->SendMessage(CPWN_XT_PUSHPINCANCEL);
Invalidate();
}
}
void CXTCaption::UpdateCaption(LPCTSTR lpszWindowText, HICON hIcon)
{
ASSERT(::IsWindow(m_hWnd));
CRect rcClient;
GetClientRect(&rcClient);
CDC* pDC = GetDC();
DrawCaptionBack(pDC, rcClient);
if (lpszWindowText != NULL)
{
m_strCaption = lpszWindowText;
UpdateCaptionText(pDC);
}
if (hIcon != NULL)
{
m_hIcon = hIcon;
DrawCaptionIcon(pDC, rcClient);
}
ReleaseDC(pDC);
}
void CXTCaption::UpdateCaptionText(CDC* pDC)
{
if (::IsWindow(m_btnCaption.m_hWnd))
{
m_btnCaption.SetWindowText(m_strCaption);
m_btnCaption.MoveWindow(GetButtonRect());
}
DrawCaptionText(pDC);
}
CRect CXTCaption::GetTextRect() const
{
if (m_strCaption.IsEmpty())
return CXTPEmptyRect();
CXTPClientRect rcClient(this);
// Use a NULL window dc to get the size the caption button
// should be using CDC::GetTextExtent(...).
CWindowDC dc(NULL);
CXTPFontDC fontDC(&dc, GetFont());
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
// Calculate the button area size.
CSize size = dc.GetTextExtent(m_strCaption, m_strCaption.GetLength());
size.cx += tm.tmAveCharWidth + 12;
size.cy = rcClient.Height();
int iWidth = rcClient.Width() - (m_hIcon ? 18 : 0);
if (size.cx > iWidth)
size.cx = iWidth;
return CRect(m_nBorder, m_nBorder, m_nBorder + size.cx, size.cy - m_nBorder);
}
CRect CXTCaption::GetButtonRect() const
{
if (!::IsWindow(m_btnCaption.m_hWnd))
return CXTPEmptyRect();
if (!HasCloseButton())
return GetTextRect();
CSize szIcon(16, 15);
CXTPClientRect rcClient(this);
CRect rcButton;
rcButton.top = (rcClient.Height()-szIcon.cy)/2;
rcButton.bottom = rcButton.top+szIcon.cy;
// ensure offset is the same for top and right edge.
int x = rcButton.top-rcClient.top;
rcButton.left = (rcClient.Width()-szIcon.cx)-x;
rcButton.right = rcButton.left+szIcon.cx;
return rcButton;
}
void CXTCaption::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)
{
CStatic::OnWindowPosChanged(lpwndpos);
if (::IsWindow(m_btnCaption.m_hWnd))
m_btnCaption.MoveWindow(GetButtonRect());
}
void CXTCaption::SetCaptionColors(COLORREF clrBorder, COLORREF clrFace, COLORREF clrText)
{
ASSERT(::IsWindow(m_hWnd));
m_bUserColors = true;
GetTheme()->m_clrBorder.SetCustomValue(clrBorder);
GetTheme()->m_clrFace.SetCustomValue(clrFace);
GetTheme()->m_clrText.SetCustomValue(clrText);
if (::IsWindow(m_btnCaption.m_hWnd))
{
m_btnCaption.SetColorFace(GetTheme()->m_clrFace);
m_btnCaption.SetColorText(GetTheme()->m_clrText);
m_btnCaption.SetColorShadow(GetTheme()->m_clrEdgeShadow);
}
}
void CXTCaption::SetOffice2003Colors(bool b2003Colors/*= true*/)
{
m_bUserColors = b2003Colors;
SetTheme(b2003Colors ? new CXTCaptionThemeOffice2003() : NULL);
}
void CXTCaption::OnSysColorChange()
{
CStatic::OnSysColorChange();
// update caption colors if not user defined.
if (m_bUserColors == false)
{
GetTheme()->RefreshMetrics();
if (::IsWindow(m_btnCaption.m_hWnd))
{
m_btnCaption.SetColorFace(GetTheme()->m_clrFace);
m_btnCaption.SetColorText(GetTheme()->m_clrText);
m_btnCaption.SetColorShadow(GetTheme()->m_clrEdgeShadow);
}
}
}