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.
518 lines
10 KiB
C++
518 lines
10 KiB
C++
// XTFlatComboBox.cpp : implementation of the CXTFlatComboBox 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/XTPMaskEditT.h"
|
|
#include "Common/XTPColorManager.h"
|
|
|
|
#include "../Util/XTPControlTheme.h"
|
|
#include "../Edit/XTPEdit.h"
|
|
|
|
#include "XTThemeManager.h"
|
|
#include "XTVC50Helpers.h"
|
|
#include "XTFlatComboBox.h"
|
|
#include "XTFlatControlsTheme.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define EVENT_TIMER 1000
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTFlatComboBox
|
|
|
|
CXTFlatComboBox::CXTFlatComboBox()
|
|
: CXTThemeManagerStyleHost(GetThemeFactoryClass())
|
|
, m_bDisableAC(FALSE)
|
|
, m_bFlatLook(TRUE)
|
|
, m_bPainted(FALSE)
|
|
, m_bHasFocus(FALSE)
|
|
, m_bAutoComp(FALSE)
|
|
, m_nStyle(0)
|
|
, m_nStyleEx(0)
|
|
, m_crBack(COLORREF_NULL)
|
|
, m_crText(COLORREF_NULL)
|
|
{
|
|
}
|
|
|
|
CXTFlatComboBox::~CXTFlatComboBox()
|
|
{
|
|
}
|
|
|
|
IMPLEMENT_THEME_HOST(CXTFlatComboBox)
|
|
IMPLEMENT_THEME_REFRESH(CXTFlatComboBox, CComboBox)
|
|
|
|
IMPLEMENT_DYNAMIC(CXTFlatComboBox, CComboBox)
|
|
|
|
BEGIN_MESSAGE_MAP(CXTFlatComboBox, CComboBox)
|
|
//{{AFX_MSG_MAP(CXTFlatComboBox)
|
|
ON_WM_TIMER()
|
|
ON_WM_PAINT()
|
|
ON_CONTROL_REFLECT_EX(CBN_SETFOCUS, OnSetFocus)
|
|
ON_CONTROL_REFLECT_EX(CBN_KILLFOCUS, OnKillFocus)
|
|
ON_WM_SETCURSOR()
|
|
ON_CONTROL_REFLECT_EX(CBN_EDITUPDATE, OnEditUpdate)
|
|
ON_CONTROL_REFLECT_EX(CBN_CLOSEUP, OnEndSel)
|
|
ON_WM_ERASEBKGND()
|
|
ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTFlatComboBox message handlers
|
|
|
|
BOOL CXTFlatComboBox::PointInRect()
|
|
{
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
CRect rc;
|
|
GetWindowRect(rc);
|
|
|
|
CPoint pt;
|
|
GetCursorPos(&pt);
|
|
|
|
return rc.PtInRect(pt);
|
|
}
|
|
|
|
BOOL CXTFlatComboBox::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
if (IsFlat() && (message == WM_MOUSEMOVE) && PointInRect())
|
|
{
|
|
SetTimer(EVENT_TIMER, 10, NULL);
|
|
OnTimer(EVENT_TIMER);
|
|
}
|
|
|
|
return CComboBox::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|
|
|
|
void CXTFlatComboBox::DisableFlatLook(BOOL bDisable)
|
|
{
|
|
if (IsFlat() == bDisable)
|
|
{
|
|
m_bFlatLook = !bDisable;
|
|
|
|
if (::IsWindow(m_hWnd))
|
|
{
|
|
if (IsFlat())
|
|
{
|
|
// save style.
|
|
m_nStyle = GetStyle() & (WS_BORDER);
|
|
m_nStyleEx = GetExStyle() & (WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
|
|
|
|
ModifyStyle(WS_BORDER, 0);
|
|
ModifyStyleEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, 0);
|
|
}
|
|
else
|
|
{
|
|
ModifyStyle(0, m_nStyle);
|
|
ModifyStyleEx(0, m_nStyleEx);
|
|
}
|
|
|
|
SetWindowPos(NULL, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOZORDER);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CXTFlatComboBox::OnTimer(UINT_PTR nIDEvent)
|
|
{
|
|
if (EVENT_TIMER == nIDEvent)
|
|
{
|
|
if (!PointInRect())
|
|
{
|
|
KillTimer(EVENT_TIMER);
|
|
|
|
if (m_bPainted == TRUE)
|
|
{
|
|
RedrawWindow();
|
|
}
|
|
|
|
m_bPainted = FALSE;
|
|
}
|
|
|
|
// on mouse over, show raised.
|
|
else if (!m_bPainted)
|
|
{
|
|
RedrawWindow();
|
|
m_bPainted = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CComboBox::OnTimer(nIDEvent);
|
|
}
|
|
}
|
|
|
|
BOOL CXTFlatComboBox::OnEraseBkgnd(CDC* /*pDC*/)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTFlatComboBox::OnPaint()
|
|
{
|
|
// do default rendering first.
|
|
CComboBox::OnPaint();
|
|
|
|
// get the client device context.
|
|
CClientDC dc(this);
|
|
DoPaint(&dc);
|
|
}
|
|
|
|
void CXTFlatComboBox::CalcClientRect(CRect& rc)
|
|
{
|
|
// deflate by 3D border, 3D edge and drop arrow (thumb).
|
|
rc.DeflateRect(GetTheme()->GetBorderSize());
|
|
rc.DeflateRect(GetTheme()->GetEdgeSize());
|
|
rc.right -= GetTheme()->GetThumbSize().cx;
|
|
}
|
|
|
|
// a helper for rendering the control appearance
|
|
void CXTFlatComboBox::DoPaint(CDC* pDC)
|
|
{
|
|
// draw theme.
|
|
if (IsFlat())
|
|
{
|
|
// Get the client rect.
|
|
CXTPClientRect r(this);
|
|
|
|
// exclude client portions from redraw.
|
|
CRect rClip(r);
|
|
CalcClientRect(rClip);
|
|
pDC->ExcludeClipRect(&rClip);
|
|
|
|
// Paint to a memory device context to help
|
|
// eliminate screen flicker.
|
|
CXTPBufferDC memDC(*pDC, r);
|
|
memDC.FillSolidRect(r, GetXtremeColor(COLOR_3DFACE));
|
|
|
|
if (m_bHasFocus || PointInRect())
|
|
{
|
|
DrawCombo(&memDC, GetDroppedState() ? xtMouseSelect : xtMouseHover);
|
|
}
|
|
else
|
|
{
|
|
DrawCombo(&memDC, xtMouseNormal);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CXTFlatComboBox::DrawCombo(CDC* pDC, XTMouseState eState)
|
|
{
|
|
GetTheme()->DrawFlatComboBox(pDC, this, eState);
|
|
}
|
|
|
|
BOOL CXTFlatComboBox::OnSetFocus()
|
|
{
|
|
if (IsFlat())
|
|
{
|
|
m_bHasFocus = TRUE;
|
|
RedrawWindow();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXTFlatComboBox::OnKillFocus()
|
|
{
|
|
if (IsFlat())
|
|
{
|
|
m_bHasFocus = FALSE;
|
|
RedrawWindow();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXTFlatComboBox::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
// Make sure that the keystrokes continue to the edit control.
|
|
if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP)
|
|
{
|
|
// if tab, return or escape key, just use default.
|
|
switch (pMsg->wParam)
|
|
{
|
|
case VK_DELETE:
|
|
case VK_BACK:
|
|
{
|
|
if (m_bAutoComp)
|
|
{
|
|
m_bDisableAC = (pMsg->message == WM_KEYDOWN);
|
|
}
|
|
break;
|
|
}
|
|
case VK_TAB:
|
|
case VK_RETURN:
|
|
case VK_ESCAPE:
|
|
{
|
|
return CComboBox::PreTranslateMessage(pMsg);
|
|
}
|
|
}
|
|
|
|
// If the combo box has an edit control, don't allow
|
|
// the framework to process accelerators, let the edit
|
|
// control handle it instead. GetEditSel() will return
|
|
// CB_ERR if there is no edit control present...
|
|
|
|
if (GetEditSel() != (DWORD)CB_ERR)
|
|
{
|
|
::TranslateMessage(pMsg);
|
|
::DispatchMessage(pMsg);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return CComboBox::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
BOOL CXTFlatComboBox::OnEditUpdate()
|
|
{
|
|
// if we are not to auto update the text, get outta here
|
|
if (m_bAutoComp)
|
|
{
|
|
if (m_bDisableAC)
|
|
{
|
|
Default();
|
|
}
|
|
else
|
|
{
|
|
// Get the text in the edit box
|
|
CString strItemTyped;
|
|
GetWindowText(strItemTyped);
|
|
int nLength = strItemTyped.GetLength();
|
|
|
|
if (nLength >= 1)
|
|
{
|
|
// Currently selected range
|
|
DWORD dwCurSel = GetEditSel();
|
|
int nStart = LOWORD(dwCurSel);
|
|
int nEnd = HIWORD(dwCurSel);
|
|
|
|
// Search for, and select in, and string in the combo box that is prefixed
|
|
// by the text in the edit box
|
|
if (SelectString(-1, strItemTyped) == CB_ERR)
|
|
{
|
|
SetWindowText(strItemTyped); // No text selected, so restore what was there before
|
|
if (dwCurSel != (DWORD)CB_ERR)
|
|
{
|
|
SetEditSel(nStart, nEnd); //restore cursor postion
|
|
}
|
|
}
|
|
|
|
// Set the text selection as the additional text that we have added
|
|
if (nEnd < nLength && dwCurSel != (DWORD)CB_ERR)
|
|
{
|
|
SetEditSel(nStart, nEnd);
|
|
}
|
|
else
|
|
{
|
|
SetEditSel(nLength, -1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXTFlatComboBox::OnEndSel()
|
|
{
|
|
if (IsFlat())
|
|
{
|
|
Invalidate();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT CXTFlatComboBox::OnPrintClient(WPARAM wp, LPARAM)
|
|
{
|
|
LRESULT lResult = Default();
|
|
|
|
CDC* pDC = CDC::FromHandle((HDC)wp);
|
|
DoPaint(pDC);
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTFlatEdit
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
IMPLEMENT_THEME_HOST(CXTFlatEdit)
|
|
IMPLEMENT_THEME_REFRESH(CXTFlatEdit, CXTEdit)
|
|
|
|
CXTFlatEdit::CXTFlatEdit()
|
|
: CXTThemeManagerStyleHost(GetThemeFactoryClass())
|
|
, m_bFlatLook(TRUE)
|
|
, m_bHasFocus(FALSE)
|
|
, m_bPainted(FALSE)
|
|
{
|
|
m_nStyle = m_nStyleEx = 0;
|
|
}
|
|
|
|
CXTFlatEdit::~CXTFlatEdit()
|
|
{
|
|
}
|
|
|
|
IMPLEMENT_DYNAMIC(CXTFlatEdit, CXTEdit)
|
|
|
|
BEGIN_MESSAGE_MAP(CXTFlatEdit, CXTEdit)
|
|
//{{AFX_MSG_MAP(CXTFlatEdit)
|
|
ON_WM_NCPAINT()
|
|
ON_WM_TIMER()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_KILLFOCUS()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTFlatEdit message handlers
|
|
|
|
BOOL CXTFlatEdit::PointInRect()
|
|
{
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
CRect rc;
|
|
GetWindowRect(rc);
|
|
|
|
CPoint pt;
|
|
GetCursorPos(&pt);
|
|
|
|
return rc.PtInRect(pt);
|
|
}
|
|
|
|
BOOL CXTFlatEdit::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
if (IsFlat() && (message == WM_MOUSEMOVE) && PointInRect())
|
|
{
|
|
SetTimer(EVENT_TIMER, 10, NULL);
|
|
OnTimer(EVENT_TIMER);
|
|
}
|
|
|
|
return CXTEdit::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|
|
|
|
void CXTFlatEdit::DisableFlatLook(BOOL bDisable)
|
|
{
|
|
if (m_bFlatLook == bDisable)
|
|
{
|
|
m_bFlatLook = !bDisable;
|
|
SendMessage(WM_NCPAINT);
|
|
}
|
|
}
|
|
|
|
void CXTFlatEdit::OnTimer(UINT_PTR nIDEvent)
|
|
{
|
|
if (EVENT_TIMER == nIDEvent)
|
|
{
|
|
if (!PointInRect())
|
|
{
|
|
KillTimer(EVENT_TIMER);
|
|
|
|
if (m_bPainted == TRUE)
|
|
{
|
|
SendMessage(WM_NCPAINT);
|
|
}
|
|
|
|
m_bPainted = FALSE;
|
|
}
|
|
|
|
// on mouse over, show raised.
|
|
else if (!m_bPainted)
|
|
{
|
|
SendMessage(WM_NCPAINT);
|
|
m_bPainted = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CXTEdit::OnTimer(nIDEvent);
|
|
}
|
|
}
|
|
|
|
void CXTFlatEdit::OnNcPaint()
|
|
{
|
|
if (IsFlat())
|
|
{
|
|
CWindowDC dc(this);
|
|
|
|
CXTPClientRect rClient(this);
|
|
CXTPWindowRect rWindow(this);
|
|
ScreenToClient(rWindow);
|
|
rClient.OffsetRect(-rWindow.left, -rWindow.top);
|
|
dc.ExcludeClipRect(rClient);
|
|
rWindow.OffsetRect(-rWindow.left, -rWindow.top);
|
|
|
|
CXTPBufferDC memDC(dc, rWindow);
|
|
dc.FillSolidRect(rWindow, IsWindowEnabled() ? GetXtremeColor(COLOR_WINDOW) : GetXtremeColor(COLOR_3DFACE));
|
|
|
|
DrawBorders(&memDC, rWindow);
|
|
}
|
|
else
|
|
{
|
|
Default();
|
|
}
|
|
}
|
|
|
|
// a helper for rendering the control appearance
|
|
void CXTFlatEdit::DrawBorders(CDC* pDC, const CRect& rWindow)
|
|
{
|
|
if (m_bHasFocus || PointInRect())
|
|
{
|
|
GetTheme()->DrawBorders(pDC, this, rWindow, xtMouseHover);
|
|
}
|
|
else
|
|
{
|
|
GetTheme()->DrawBorders(pDC, this, rWindow, xtMouseNormal);
|
|
}
|
|
}
|
|
|
|
void CXTFlatEdit::OnSetFocus(CWnd* pOldWnd)
|
|
{
|
|
CXTEdit::OnSetFocus(pOldWnd);
|
|
|
|
if (IsFlat())
|
|
{
|
|
m_bHasFocus = TRUE;
|
|
Invalidate();
|
|
SendMessage(WM_NCPAINT);
|
|
}
|
|
}
|
|
|
|
void CXTFlatEdit::OnKillFocus(CWnd* pNewWnd)
|
|
{
|
|
CXTEdit::OnKillFocus(pNewWnd);
|
|
|
|
if (IsFlat())
|
|
{
|
|
m_bHasFocus = FALSE;
|
|
Invalidate();
|
|
SendMessage(WM_NCPAINT);
|
|
}
|
|
}
|