You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

638 lines
14 KiB
C++

// XTPCaption.cpp : implementation of the CXTPCaption class.
//
// This file is a part of the XTREME CONTROLS MFC class library.
// (c)1998-2012 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/XTPDrawHelpers.h"
#include "Common/XTPColorManager.h"
#include "../Util/XTPControlTheme.h"
#include "../Resource.h"
#include "../Defines.h"
#include "../Util/XTPUtil.h"
#include "../Util/XTPGlobal.h"
#include "../Button/XTPButton.h"
#include "../Button/XTPButtonTheme.h"
#include "XTPCaptionTheme.h"
#include "XTPCaption.h"
#include "XTPCaptionPopupWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CXTPCaptionButton
CXTPCaptionButton::CXTPCaptionButton()
: m_pCaption(NULL)
{
}
/////////////////////////////////////////////////////////////////////////////
// CXTPCaption
CXTPCaption::CXTPCaption()
: m_pTheme(NULL)
{
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(XTPAuxData().cxSmIcon, 16);
m_sizeIcon.cy = __min(XTPAuxData().cySmIcon, 16);
m_dwExStyle = 0L;
m_clrText = ::GetSysColor(COLOR_BTNTEXT);
m_clrBorder = ::GetSysColor(COLOR_3DFACE);
m_clrFace = ::GetSysColor(COLOR_3DFACE);
VERIFY(SetTheme(xtpControlThemeDefault));
}
CXTPCaption::~CXTPCaption()
{
CMDTARGET_RELEASE(m_pTheme);
}
IMPLEMENT_DYNAMIC(CXTPCaption, CStatic)
BEGIN_MESSAGE_MAP(CXTPCaption, CStatic)
//{{AFX_MSG_MAP(CXTPCaption)
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(XTP_IDC_BTN_CLOSE, OnCaptButton)
ON_MESSAGE_VOID(CPN_XTP_PUSHPINBUTTON, OnPushPinButton)
ON_MESSAGE_VOID(CPN_XTP_PUSHPINCANCEL, OnPushPinCancel)
ON_MESSAGE(WM_XTP_SETCONTROLTHEME, OnSetTheme)
END_MESSAGE_MAP()
void CXTPCaption::RefreshMetrics()
{
if (m_pTheme)
m_pTheme->RefreshMetrics(this);
if (::IsWindow(m_hWnd))
RedrawWindow();
}
BOOL CXTPCaptionButton::SetTheme(XTPControlTheme eTheme)
{
CMDTARGET_RELEASE(m_pTheme);
switch (eTheme)
{
case xtpControlThemeOfficeXP:
m_pTheme = new CXTPCaptionButtonThemeOfficeXP();
break;
case xtpControlThemeOffice2003:
m_pTheme = new CXTPCaptionButtonThemeOffice2003();
break;
default:
m_pTheme = new CXTPCaptionButtonTheme();
}
RefreshMetrics();
return (m_pTheme != NULL);
}
BOOL CXTPCaption::SetTheme(CXTPCaptionTheme* pTheme)
{
CMDTARGET_RELEASE(m_pTheme);
m_pTheme = pTheme;
m_btnCaption.SetTheme(pTheme->GetThemeStyle());
RefreshMetrics();
return (m_pTheme != NULL);
}
BOOL CXTPCaption::SetTheme(XTPControlTheme eTheme)
{
switch (eTheme)
{
case xtpControlThemeOfficeXP:
return SetTheme(new CXTPCaptionThemeOfficeXP());
case xtpControlThemeOffice2003:
return SetTheme(new CXTPCaptionThemeOffice2003());
}
return SetTheme(new CXTPCaptionTheme());
}
LRESULT CXTPCaption::OnSetTheme(WPARAM wParam, LPARAM /*lParam*/)
{
XTPControlTheme eTheme = (XTPControlTheme)wParam;
SetTheme(eTheme);
return 0;
}
BOOL CXTPCaption::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
if (message == WM_SETTINGCHANGE || message == WM_SYSCOLORCHANGE)
{
RefreshMetrics();
}
return CStatic::OnWndMsg(message, wParam, lParam, pResult);
}
void CXTPCaption::OnSize(UINT nType, int cx, int cy)
{
CStatic::OnSize(nType, cx, cy);
if (m_hIcon != NULL)
RedrawWindow();
}
void CXTPCaption::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 CXTPCaption::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 CXTPCaption::OnEraseBkgnd(CDC* /*pDC*/)
{
return TRUE;
}
void CXTPCaption::DrawCaptionBack(CDC* pDC, CRect& rcItem)
{
GetTheme()->DrawCaptionBack(pDC, this, rcItem);
}
void CXTPCaption::DrawCaptionText(CDC* pDC)
{
GetTheme()->DrawCaptionText(pDC, this);
}
void CXTPCaption::DrawCaptionIcon(CDC* pDC, CRect& rcItem)
{
GetTheme()->DrawCaptionIcon(pDC, this, rcItem);
}
BOOL CXTPCaption::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(&XTPAuxData().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_CENTER | BS_VCENTER,
CRect(0, 0, 0, 0), this, XTP_IDC_BTN_CLOSE))
{
TRACE0("Unable to create caption button.\n");
return -1;
}
// Create the image list used by frame buttons.
m_ilButton.Create (XTP_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_VCENTER,
CRect(0, 0, 0, 0), this, XTP_IDC_BTN_CLOSE))
{
TRACE0("Unable to create caption button.\n");
return FALSE;
}
m_bAppCaption = true;
}
m_btnCaption.SetCaption(this);
SetWindowPos(NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);
return TRUE;
}
void CXTPCaption::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 CXTPCaption::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 CXTPCaption::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 CXTPCaption::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 CXTPCaptionPopupWnd;
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();
m_pPopupWnd->SetTheme(m_pTheme->GetThemeStyle());
// press the caption button.
m_btnCaption.SetState(TRUE);
return TRUE;
}
void CXTPCaption::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 CXTPCaption::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(CPN_XTP_PUSHPINBUTTON);
Invalidate();
}
}
void CXTPCaption::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(CPN_XTP_PUSHPINCANCEL);
Invalidate();
}
}
void CXTPCaption::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 CXTPCaption::UpdateCaptionText(CDC* pDC)
{
if (::IsWindow(m_btnCaption.m_hWnd))
{
m_btnCaption.SetWindowText(m_strCaption);
m_btnCaption.MoveWindow(GetButtonRect());
}
DrawCaptionText(pDC);
}
CRect CXTPCaption::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 CXTPCaption::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 CXTPCaption::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)
{
CStatic::OnWindowPosChanged(lpwndpos);
if (::IsWindow(m_btnCaption.m_hWnd))
m_btnCaption.MoveWindow(GetButtonRect());
}
void CXTPCaption::SetCaptionColors(COLORREF clrBorder, COLORREF clrFace, COLORREF clrText)
{
ASSERT(::IsWindow(m_hWnd));
m_bUserColors = true;
m_clrBorder = clrBorder;
m_clrFace = clrFace;
m_clrText = clrText;
if (::IsWindow(m_btnCaption.m_hWnd))
{
// m_btnCaption.SetColorFace(m_clrFace);
// m_btnCaption.SetColorText(m_clrText);
// m_btnCaption.SetColorShadow(::GetSysColor(COLOR_3DDKSHADOW));
}
}
void CXTPCaption::SetOffice2003Colors(bool b2003Colors/*= true*/)
{
m_bUserColors = b2003Colors;
SetTheme(b2003Colors ? xtpControlThemeOffice2003 : xtpControlThemeDefault);
}
void CXTPCaption::OnSysColorChange()
{
CStatic::OnSysColorChange();
// update caption colors if not user defined.
if (m_bUserColors == false)
{
m_clrText = ::GetSysColor(COLOR_BTNTEXT);
m_clrBorder = ::GetSysColor(COLOR_3DFACE);
m_clrFace = ::GetSysColor(COLOR_3DFACE);
}
}