891 lines
25 KiB
C++
891 lines
25 KiB
C++
// ==========================================================================
|
|
// Class Specification : COXDropEdit
|
|
// ==========================================================================
|
|
|
|
// Header file : OXDropEdit.h
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/*
|
|
|
|
DESCRIPTION
|
|
|
|
|
|
COXDropEdit is template class that provides the functionality of adding dropdown button
|
|
to any edit control. Dropdown button is displayed on the right or left side of the
|
|
edit box and takes all height of the control window. The width of the dropdown button
|
|
can be set programmatically (by default we use the width of the current width of
|
|
the scroll bar).
|
|
|
|
The dropdown button is clickable and combination of 'pressed down' and 'unpressed'
|
|
events would generate 'dropdown' event that can be handled by a programmer. By default,
|
|
COXDropEdit class allows you to display associated menu (see below how to associate
|
|
a menu with COXDropEdit).
|
|
|
|
At any time you can hide or show the dropdown button. Internally, the dropdown button
|
|
resides in the non-client area so this class can be safely used with most of
|
|
customized edit controls. E.g. you can use it with our extended controls (COXEdit,
|
|
COXNumericEdit, COXCurrencyEdit, COXMaskedEdit) without any problems. In fact, we've
|
|
updated our COXPhysicalEdit class to be derived from COXDropEdit in order to provide the
|
|
functionality of changing the base unit by clicking on the dropdown button and choosing
|
|
the unit from the popup menu.
|
|
|
|
|
|
A programmer would normally use COXDropEdit class in order to derive from it.
|
|
Let's go through the steps of creating a simple edit control that will display
|
|
popup menu as a result of clicking the dropdown button and after a user choose
|
|
an item in the menu the text in the edit box will be updated orrespondingly.
|
|
|
|
1) Derive your own class from COXDropEdit using any existing edit class as the base one:
|
|
|
|
class CMenuEdit: public COXDropEdit<CEdit>
|
|
|
|
In this case we declare the class that would use standard CEdit as the base class
|
|
|
|
|
|
2) Declare the following protected virtual function in the class that will be called
|
|
every time the dropdown button is clicked:
|
|
|
|
virtual void OnDropButton();
|
|
|
|
In our case we would use the default implementation of this function as long as we
|
|
are going to display the menu (this functionality provided by COXDropEdit by default).
|
|
But, generally, you can put here any functionality you please: e.g display popup
|
|
window or dialog.
|
|
|
|
void CMenuEdit::OnDropButton()
|
|
{
|
|
COXDropEdit<CEdit>::OnDropButton();
|
|
}
|
|
|
|
|
|
3) Declare the following protected member for the popup menu that will be displayed
|
|
when the dropdown button is clicked:
|
|
|
|
CMenu m_menu;
|
|
|
|
In order to associate a menu with COXDropEdit object you have to call the
|
|
following COXDropEdit function:
|
|
|
|
AssociateMenu();
|
|
|
|
and the pointer to the associated menu can be retrieved using this function:
|
|
|
|
GetAssociatedMenu();
|
|
|
|
|
|
4) So we need to create popup menu and associate it with the object. We suggest
|
|
you can do that in the following COXDropEdit protected virtual function that
|
|
should be overridden in CMenuEdit class:
|
|
|
|
virtual BOOL InitializeDropEdit();
|
|
|
|
This function is called right after creation or subclassing of existed control.
|
|
Primarily it was designed in order to provide a programmer with the functionality
|
|
that can be used in order to safely initialize the control. This function must
|
|
return TRUE if the control has been successfully initialized or FALSE otherwise.
|
|
In your implementation you must call the parent implementation first of all.
|
|
|
|
BOOL CMenuEdit::InitializeDropEdit()
|
|
{
|
|
if(!COXDropEdit<CEdit>::InitializeDropEdit())
|
|
return FALSE;
|
|
|
|
if(!m_menu.CreatePopupMenu())
|
|
return FALSE;
|
|
for(int nIndex=1; nIndex<=10; nIndex++)
|
|
{
|
|
CString sMenuText;
|
|
sMenuText.Format(_T("Item %d"),nIndex);
|
|
m_menu.AppendMenu(MF_STRING,nIndex,sMenuText);
|
|
}
|
|
AssociateMenu(&m_menu);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
5) In our case we display popup menu as a result of dropdown event.
|
|
In order to handle the process of choosing the menu item we have to provide
|
|
WM_COMMAND handler for the class using ON_COMMAND_RANGE() or ON_COMMAND() macro.
|
|
In our case our actions are not going to depend on the chosen item so we would
|
|
define our handler as follows:
|
|
|
|
afx_msg void OnMenuSelect(UINT nID);
|
|
. . . . . . . . . . . . . . . . . .
|
|
BEGIN_MESSAGE_MAP(CMenuEdit, CEdit)
|
|
//{{AFX_MSG_MAP(CMenuEdit)
|
|
//}}AFX_MSG_MAP
|
|
ON_COMMAND_RANGE(1,10,OnMenuSelect)
|
|
END_MESSAGE_MAP()
|
|
. . . . . . . . . . . . . . . . . .
|
|
void CMenuEdit::OnMenuSelect(UINT nID)
|
|
{
|
|
CString sItem;
|
|
m_menu.GetMenuString(nID,sItem,MF_BYCOMMAND);
|
|
CString sText;
|
|
sText.Format(_T("<%s> has been picked"),sItem);
|
|
|
|
SetWindowText(sText);
|
|
}
|
|
|
|
|
|
|
|
6) Basically we went through all the major steps that should be taken in order to
|
|
implement COXDropEdit derived object. Below you will find information about
|
|
some useful COXDropEdit functions that you might want to use in your applications:
|
|
|
|
- the following two protected virtual functions can be overridden in order
|
|
to customize the appearance of the dropdown button:
|
|
|
|
virtual CRect DrawButtonFrame(CDC* pDC, CRect rect, BOOL bPressed);
|
|
virtual void DrawButtonImage(CDC* pDC, CRect rect, BOOL bPressed);
|
|
|
|
|
|
- the following functions can be used in order to set/retrieve the width
|
|
of the dropdown button:
|
|
|
|
SetButtonWidth();
|
|
GetButtonWidth();
|
|
|
|
|
|
- these functions can be used in order to show/hide the dropdown button and
|
|
to retrieve the flag that specifies the visibility of the dropdown button:
|
|
|
|
void ShowButton();
|
|
BOOL IsButtonVisible();
|
|
|
|
|
|
For details refer to the COXDropEdit class reference.
|
|
|
|
|
|
|
|
As we mentioned before we use COXDropEdit derivation with our COXPhysicalEdit class.
|
|
Also we designed and implemented a number of COXDropEdit derived classes with predefined
|
|
functionality. These classes are: COXBrowseColorEdit (edit control with color picker
|
|
using our COXColorPickerCtrl), COXBrowseDirEdit (edit control with Directory Picker
|
|
using our COXFolderPicker), COXBrowseDirEdit16 (edit control with Directory Picker
|
|
using our COXDirectoryDialog), COXBrowseFileEdit (edit control with File Picker using
|
|
standard CFileDialog).
|
|
|
|
|
|
|
|
Take a look at the ExtendedEditControls sample that can be found in the
|
|
.\Samples\gui\ExtendedEditControls subdirectory of your Ultimate Toolbox directory.
|
|
In the sample check out the 'Physical Edit' and 'Drop Edit' pages that demonstrate the
|
|
power of COXDropEdit class.
|
|
|
|
|
|
|
|
Dependencies:
|
|
#include "OXDropEdit.h"
|
|
|
|
|
|
*/
|
|
|
|
#if !defined(_OXDROPEDIT_H__)
|
|
#define _OXDROPEDIT_H__
|
|
|
|
#if _MSC_VER > 1000
|
|
#pragma once
|
|
#endif // _MSC_VER > 1000
|
|
|
|
#include "OXDllExt.h"
|
|
#include <Windowsx.h>
|
|
|
|
// dropbutton alignment
|
|
#define OXDROPEDIT_BUTTONRIGHT 0
|
|
#define OXDROPEDIT_BUTTONLEFT 1
|
|
|
|
// timer for checking the state of the button (pressed or unpressed)
|
|
#define IDT_OXDROPEDIT_CHECKBUTTONSTATE 227
|
|
#define ID_OXDROPEDIT_TIMER_DELAY 200
|
|
|
|
// system keys state
|
|
#define PRESSEDIN_CONTROL 0x00000001
|
|
#define PRESSEDIN_SHIFT 0x00000002
|
|
#define PRESSEDIN_ALT 0x00000004
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXDropEdit window
|
|
|
|
template<class PARENTEDIT>
|
|
class COXDropEdit : public PARENTEDIT
|
|
{
|
|
// Construction
|
|
public:
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Constructs the object
|
|
COXDropEdit();
|
|
|
|
// Attributes
|
|
public:
|
|
|
|
protected:
|
|
// button alignment (left or right)
|
|
int m_nButtonAlignment;
|
|
// button width
|
|
int m_nButtonWidth;
|
|
// flag that specifies whether the button is visible or not
|
|
BOOL m_bShowButton;
|
|
// flag that specifies button state
|
|
BOOL m_bButtonPressed;
|
|
// flag that specifies that at the time of last check mouse cursor
|
|
// was over the dropdown button
|
|
BOOL m_bMouseWasOver;
|
|
|
|
// internal flag that specifies whether the window is needed to be
|
|
// properly initialized
|
|
BOOL m_bInitializedDropEdit;
|
|
// internal flag that specifies that process of creation has been finished
|
|
BOOL m_bCreated;
|
|
|
|
|
|
// if control must recalc its size in order to make room for dropdown button
|
|
BOOL m_bForceToRecalc;
|
|
|
|
// timer to check the state of a dropdown button
|
|
UINT_PTR m_nTimerToCheckButtonState;
|
|
|
|
// menu to be displayed as result of drop button event
|
|
CMenu* m_pMenu;
|
|
|
|
// virtual code of the key that used to emulate the process of clicking on
|
|
// the button. The value of m_dwDropdownKeyState member is also checked which
|
|
// determines what system key(s) must be also pressed in.
|
|
int m_nVCDropdownKey;
|
|
|
|
// state of the "Ctrl", "Shift", "Alt" keys when m_nVCDropdownKey key is pressed in.
|
|
// Can be zero or any combination of folowing flags:
|
|
//
|
|
// PRESSEDIN_CONTROL - "Ctrl" key must be pressed in
|
|
// PRESSEDIN_SHIFT - "Shift" key must be pressed in
|
|
// PRESSEDIN_ALT - "Alt" key must be pressed in
|
|
DWORD m_dwDropdownKeyState;
|
|
|
|
|
|
// Operations
|
|
public:
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: The width of the dropdown button in pixels
|
|
// --- Effect : Retrieves the width of the dropdown button
|
|
inline int GetButtonWidth() const { return m_nButtonWidth; }
|
|
|
|
// --- In : nButtonWidth - new width of the dropdown button in pixels
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Sets the width of the dropdown button
|
|
inline void SetButtonWidth(int nButtonWidth)
|
|
{
|
|
if(m_nButtonWidth!=nButtonWidth)
|
|
{
|
|
m_nButtonWidth=nButtonWidth;
|
|
ForceToRecalcLayout();
|
|
}
|
|
}
|
|
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: TRUE if dropdown button is displayed or FALSE otherwise
|
|
// --- Effect : Retrieves the flag that specifies the visibility
|
|
// of the dropdown button
|
|
inline BOOL IsButtonVisible() const { return m_bShowButton; }
|
|
|
|
// --- In : bShowButton - if TRUE then the dropdown button will be displayed,
|
|
// if FALSE - hidden
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Shows/Hides the dropdown button
|
|
inline void ShowButton(BOOL bShowButton)
|
|
{
|
|
if(m_bShowButton!=bShowButton)
|
|
{
|
|
m_bShowButton=bShowButton;
|
|
ForceToRecalcLayout();
|
|
}
|
|
}
|
|
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: The dropdown button alignment. Could be one of the followinfg:
|
|
//
|
|
// OXDROPEDIT_BUTTONRIGHT - the dropdown button will be
|
|
// located on the right side of
|
|
// the control
|
|
// OXDROPEDIT_BUTTONLEFT - the dropdown button will be
|
|
// located on the left side of
|
|
// the control
|
|
// --- Effect : Retrieves the value that specifies the position of the dropdown
|
|
// button in the control
|
|
inline int GetButtonAlignment() const { return m_nButtonAlignment; }
|
|
|
|
// --- In : nButtonAlignment - The new dropdown button alignment. Could be
|
|
// one of the followinfg:
|
|
//
|
|
// OXDROPEDIT_BUTTONRIGHT - the dropdown button will be
|
|
// located on the right side of
|
|
// the control
|
|
// OXDROPEDIT_BUTTONLEFT - the dropdown button will be
|
|
// located on the left side of
|
|
// the control
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Sets the value that specifies the position of the dropdown
|
|
// button in the control
|
|
inline void SetButtonAlignment(int nButtonAlignment)
|
|
{
|
|
if(m_nButtonAlignment!=nButtonAlignment)
|
|
{
|
|
m_nButtonAlignment=nButtonAlignment;
|
|
ForceToRecalcLayout();
|
|
}
|
|
}
|
|
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: pointer to the associated menu that will be displayed when
|
|
// the dropdown button is pressed if any was set using AssociateMenu()
|
|
// function, or NULL if there is no menu associated with the control
|
|
// --- Effect : Retrieves the pointer to the associated menu. If any menu is
|
|
// associated with the control then it will be automatically activated
|
|
// whenever the dropdown button is pressed
|
|
inline CMenu* GetAssociatedMenu() const { return m_pMenu; }
|
|
|
|
// --- In : pMenu - pointer to created popup menu that will be displayed
|
|
// when the dropdown button is pressed
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Assotiates the specified menu with the control. The menu
|
|
// associated with the control will be automatically activated
|
|
// whenever the dropdown button is pressed
|
|
void AssociateMenu(const CMenu* pMenu);
|
|
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Recalculates the layout of the control
|
|
inline void ForceToRecalcLayout() {
|
|
if(::IsWindow(GetSafeHwnd()))
|
|
{
|
|
::SetWindowPos(GetSafeHwnd(),NULL,0,0,0,0,
|
|
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
|
|
}
|
|
}
|
|
|
|
|
|
// --- In : nVCDropdownKey - virtual-key code of the button that
|
|
// can be used in combination with pressed in
|
|
// 'Alt' key in order to emulate clicking
|
|
// on the dropdown button
|
|
// dwKeyState - state of the "Ctrl", "Shift", "Alt" keys
|
|
// when nVCDropdownKey key is pressed. Can be
|
|
// zero or any combination of following flags:
|
|
//
|
|
// PRESSEDIN_CONTROL - "Ctrl" key must be pressed
|
|
// PRESSEDIN_SHIFT - "Shift" key must be pressed
|
|
// PRESSEDIN_ALT - "Alt" key must be pressed
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Sets the virtual-key code of the button that can be used in
|
|
// combination with pressed in 'Alt' key in order to emulate clicking
|
|
// on the dropdown button
|
|
inline void SetDropdownKey(const int nVCDropdownKey,
|
|
DWORD dwKeyState=PRESSEDIN_ALT)
|
|
{
|
|
m_nVCDropdownKey=nVCDropdownKey;
|
|
m_dwDropdownKeyState=dwKeyState;
|
|
}
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: Virtual-key code of the button that can be used in order to
|
|
// emulate clicking on the dropdown button
|
|
// --- Effect : Retrieves the virtual-key code of the key that can be used
|
|
// in order to emulate clicking on the dropdown button
|
|
inline int GetDropdownKey() const
|
|
{
|
|
return m_nVCDropdownKey;
|
|
}
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: State of the "Ctrl", "Shift", "Alt" keys when dropdown key is
|
|
// pressed. Can be zero or any combination of following flags:
|
|
//
|
|
// PRESSEDIN_CONTROL - "Ctrl" key must be pressed
|
|
// PRESSEDIN_SHIFT - "Shift" key must be pressed
|
|
// PRESSEDIN_ALT - "Alt" key must be pressed
|
|
//
|
|
// --- Effect : Retrieves the state of the system keys that that they must be in
|
|
// when dropdown key is pressed
|
|
inline DWORD GetDropdownKeyState() const
|
|
{
|
|
return m_dwDropdownKeyState;
|
|
}
|
|
|
|
// Overrides
|
|
// ClassWizard generated virtual function overrides
|
|
//{{AFX_VIRTUAL(COXDropEdit)
|
|
//}}AFX_VIRTUAL
|
|
|
|
// Implementation
|
|
public:
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Destructs the object
|
|
virtual ~COXDropEdit();
|
|
|
|
|
|
// --- In : ptTest - point (in screen coordinates) to test it it lays
|
|
// in the dropdown button rectangle
|
|
// --- Out :
|
|
// --- Returns: TRUE if specified point lays in the dropdown button rectangle
|
|
// --- Effect : Retrieves the flag that defines if specified point in screen
|
|
// coordinates lays in the dropdown button rectangle
|
|
BOOL HitButtonTest(CPoint ptTest);
|
|
|
|
protected:
|
|
// called every time button is pressed
|
|
virtual void OnDropButton();
|
|
|
|
// initialize control
|
|
virtual BOOL InitializeDropEdit();
|
|
|
|
// calculates dropdown button coordinates based on the control position,
|
|
// button alignment and button width
|
|
CRect CalcButtonRect() const;
|
|
|
|
// called every time button border must be drawn
|
|
virtual CRect DrawButtonFrame(CDC* pDC, CRect rect, BOOL bPressed);
|
|
// called every time button image must be drawn
|
|
virtual void DrawButtonImage(CDC* pDC, CRect rect, BOOL bPressed);
|
|
|
|
protected:
|
|
// is handled in order to properly initialize the subclassed window
|
|
virtual void PreSubclassWindow();
|
|
// handles some messages that are important for internal implementation
|
|
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PARENTEDIT>
|
|
COXDropEdit<PARENTEDIT>::COXDropEdit()
|
|
{
|
|
if(!PARENTEDIT::IsKindOf(RUNTIME_CLASS(CEdit)))
|
|
{
|
|
TRACE(_T("COXDropEdit<PARENTEDIT>::COXDropEdit: Parent class must be CEdit derived\n"));
|
|
AfxThrowNotSupportedException();
|
|
}
|
|
m_bShowButton=TRUE;
|
|
m_nButtonAlignment=OXDROPEDIT_BUTTONRIGHT;
|
|
m_nButtonWidth=::GetSystemMetrics(SM_CXHTHUMB);
|
|
m_bButtonPressed=FALSE;
|
|
|
|
m_bInitializedDropEdit=FALSE;
|
|
m_bCreated=FALSE;
|
|
|
|
m_bForceToRecalc=FALSE;
|
|
|
|
m_nTimerToCheckButtonState=0;
|
|
|
|
m_pMenu=NULL;
|
|
|
|
m_nVCDropdownKey=VK_RETURN;
|
|
m_dwDropdownKeyState=PRESSEDIN_ALT;
|
|
|
|
m_bMouseWasOver=FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
COXDropEdit<PARENTEDIT>::~COXDropEdit()
|
|
{
|
|
}
|
|
|
|
template<class PARENTEDIT>
|
|
LRESULT COXDropEdit<PARENTEDIT>::WindowProc(UINT message, WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
#if defined (_WINDLL)
|
|
#if defined (_AFXDLL)
|
|
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
|
#else
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
ASSERT_VALID(this);
|
|
|
|
if(!m_bInitializedDropEdit && m_bCreated)
|
|
{
|
|
m_bInitializedDropEdit=TRUE;
|
|
InitializeDropEdit();
|
|
}
|
|
|
|
if(m_bForceToRecalc)
|
|
{
|
|
m_bForceToRecalc=FALSE;
|
|
ForceToRecalcLayout();
|
|
}
|
|
|
|
switch(message)
|
|
{
|
|
case WM_DESTROY:
|
|
{
|
|
if(m_nTimerToCheckButtonState!=0)
|
|
{
|
|
KillTimer(m_nTimerToCheckButtonState);
|
|
m_nTimerToCheckButtonState=0;
|
|
}
|
|
break;
|
|
}
|
|
case WM_NCCALCSIZE:
|
|
{
|
|
LRESULT lResult=PARENTEDIT::WindowProc(message, wParam, lParam);
|
|
// add an offset
|
|
if(IsButtonVisible())
|
|
{
|
|
LPNCCALCSIZE_PARAMS lpncsp=(LPNCCALCSIZE_PARAMS)lParam;
|
|
if(lpncsp->rgrc[0].right-lpncsp->rgrc[0].left>GetButtonWidth())
|
|
{
|
|
if(GetButtonAlignment()==OXDROPEDIT_BUTTONRIGHT)
|
|
lpncsp->rgrc[0].right-=GetButtonWidth();
|
|
else
|
|
lpncsp->rgrc[0].left+=GetButtonWidth();
|
|
}
|
|
else
|
|
{
|
|
lpncsp->rgrc[0].right=lpncsp->rgrc[0].left;
|
|
}
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
|
|
case WM_NCPAINT:
|
|
case WM_PAINT:
|
|
{
|
|
LRESULT lResult=PARENTEDIT::WindowProc(message, wParam, lParam);
|
|
if(IsButtonVisible())
|
|
{
|
|
CWindowDC dc(this);
|
|
CRect rectWindow;
|
|
GetWindowRect(rectWindow);
|
|
ScreenToClient(rectWindow);
|
|
CRect rectButton=CalcButtonRect();
|
|
rectButton-=rectWindow.TopLeft();
|
|
rectButton=DrawButtonFrame(&dc,rectButton,
|
|
m_bButtonPressed&m_bMouseWasOver);
|
|
DrawButtonImage(&dc,rectButton,
|
|
m_bButtonPressed&m_bMouseWasOver);
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
|
|
case WM_NCHITTEST:
|
|
{
|
|
if(HitButtonTest(CPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam))))
|
|
{
|
|
return (LRESULT)HTBORDER;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
case WM_NCLBUTTONDOWN:
|
|
{
|
|
LRESULT lResult=PARENTEDIT::WindowProc(message, wParam, lParam);
|
|
|
|
if(!IsWindowEnabled() || (GetStyle()&ES_READONLY))
|
|
return lResult;
|
|
|
|
if(HitButtonTest(CPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam))))
|
|
{
|
|
m_bButtonPressed=TRUE;
|
|
m_bMouseWasOver=TRUE;
|
|
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME);
|
|
|
|
m_nTimerToCheckButtonState=SetTimer(IDT_OXDROPEDIT_CHECKBUTTONSTATE,
|
|
ID_OXDROPEDIT_TIMER_DELAY,NULL);
|
|
if(m_nTimerToCheckButtonState==0)
|
|
{
|
|
TRACE(_T("COXDropEdit::WindowProc: failed to set timer for checking the sate of the dropdown button\n"));
|
|
}
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
|
|
case WM_NCLBUTTONUP:
|
|
{
|
|
LRESULT lResult=PARENTEDIT::WindowProc(message, wParam, lParam);
|
|
if(HitButtonTest(CPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam))))
|
|
{
|
|
if(m_bButtonPressed)
|
|
{
|
|
m_bButtonPressed=FALSE;
|
|
m_bMouseWasOver=FALSE;
|
|
if(m_nTimerToCheckButtonState!=0)
|
|
{
|
|
KillTimer(m_nTimerToCheckButtonState);
|
|
m_nTimerToCheckButtonState=0;
|
|
}
|
|
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME);
|
|
OnDropButton();
|
|
}
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
|
|
case WM_KEYDOWN:
|
|
case WM_SYSKEYDOWN:
|
|
{
|
|
if(!IsWindowEnabled() || (GetStyle()&ES_READONLY))
|
|
break;
|
|
|
|
if((int)wParam==GetDropdownKey())
|
|
{
|
|
BOOL bKeyState=TRUE;
|
|
if((m_dwDropdownKeyState&PRESSEDIN_CONTROL)!=0)
|
|
bKeyState&=(GetKeyState(VK_CONTROL)<0);
|
|
if((m_dwDropdownKeyState&PRESSEDIN_SHIFT)!=0)
|
|
bKeyState&=(GetKeyState(VK_SHIFT)<0);
|
|
if((m_dwDropdownKeyState&PRESSEDIN_ALT)!=0)
|
|
bKeyState&=(GetKeyState(VK_MENU)<0);
|
|
|
|
if(bKeyState)
|
|
{
|
|
if(m_bButtonPressed)
|
|
{
|
|
m_bButtonPressed=FALSE;
|
|
m_bMouseWasOver=FALSE;
|
|
if(m_nTimerToCheckButtonState!=0)
|
|
{
|
|
KillTimer(m_nTimerToCheckButtonState);
|
|
m_nTimerToCheckButtonState=0;
|
|
}
|
|
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME);
|
|
}
|
|
OnDropButton();
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
case WM_TIMER:
|
|
{
|
|
if(wParam==(WPARAM)m_nTimerToCheckButtonState)
|
|
{
|
|
if(m_bButtonPressed)
|
|
{
|
|
if(GetKeyState(VK_LBUTTON)<0)
|
|
{
|
|
CPoint ptCursor;
|
|
::GetCursorPos(&ptCursor);
|
|
if(HitButtonTest(ptCursor) && !m_bMouseWasOver)
|
|
{
|
|
m_bMouseWasOver=TRUE;
|
|
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME);
|
|
}
|
|
else if(!HitButtonTest(ptCursor) && m_bMouseWasOver)
|
|
{
|
|
m_bMouseWasOver=FALSE;
|
|
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bButtonPressed=FALSE;
|
|
if(m_nTimerToCheckButtonState!=0)
|
|
{
|
|
KillTimer(m_nTimerToCheckButtonState);
|
|
m_nTimerToCheckButtonState=0;
|
|
}
|
|
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
LRESULT lResult=PARENTEDIT::WindowProc(message, wParam, lParam);
|
|
|
|
if(message==WM_CREATE)
|
|
m_bCreated=TRUE;
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
void COXDropEdit<PARENTEDIT>::PreSubclassWindow()
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
_AFX_THREAD_STATE* pThreadState=AfxGetThreadState();
|
|
// hook not already in progress
|
|
if(pThreadState->m_pWndInit==NULL && !m_bInitializedDropEdit)
|
|
{
|
|
m_bInitializedDropEdit=TRUE;
|
|
InitializeDropEdit();
|
|
m_bForceToRecalc=TRUE;
|
|
}
|
|
|
|
PARENTEDIT::PreSubclassWindow();
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
BOOL COXDropEdit<PARENTEDIT>::InitializeDropEdit()
|
|
{
|
|
ASSERT(::IsWindow(GetSafeHwnd()));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
CRect COXDropEdit<PARENTEDIT>::CalcButtonRect() const
|
|
{
|
|
ASSERT(::IsWindow(GetSafeHwnd()));
|
|
|
|
CRect rect(0,0,0,0);
|
|
|
|
if(IsButtonVisible())
|
|
{
|
|
GetClientRect(rect);
|
|
if(GetButtonAlignment()==OXDROPEDIT_BUTTONRIGHT)
|
|
{
|
|
rect.left=rect.right;
|
|
rect.right=rect.left+GetButtonWidth();
|
|
}
|
|
else
|
|
{
|
|
rect.right=rect.left;
|
|
rect.left=rect.right-GetButtonWidth();
|
|
}
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
void COXDropEdit<PARENTEDIT>::OnDropButton()
|
|
{
|
|
if(m_pMenu!=NULL)
|
|
{
|
|
ASSERT((HMENU)*m_pMenu!=NULL);
|
|
|
|
CRect rect;
|
|
GetWindowRect(rect);
|
|
CPoint ptOrigin=rect.BottomRight();
|
|
UINT nFlags=TPM_RIGHTALIGN;
|
|
if(GetButtonAlignment()==OXDROPEDIT_BUTTONLEFT)
|
|
{
|
|
ptOrigin.x=rect.left;
|
|
nFlags=TPM_LEFTALIGN;
|
|
}
|
|
m_pMenu->TrackPopupMenu(nFlags,ptOrigin.x,ptOrigin.y,this);
|
|
SetFocus();
|
|
}
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
void COXDropEdit<PARENTEDIT>::AssociateMenu(const CMenu* pMenu)
|
|
{
|
|
if(pMenu!=NULL)
|
|
{
|
|
ASSERT((HMENU)*pMenu!=NULL);
|
|
}
|
|
|
|
m_pMenu=(CMenu*)pMenu;
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
CRect COXDropEdit<PARENTEDIT>::DrawButtonFrame(CDC* pDC, CRect rect, BOOL bPressed)
|
|
{
|
|
ASSERT(pDC!=NULL);
|
|
|
|
COLORREF clrTopLeft=(bPressed ? ::GetSysColor(COLOR_BTNSHADOW) :
|
|
::GetSysColor(COLOR_BTNHILIGHT));
|
|
COLORREF clrBottomRight=(bPressed ? ::GetSysColor(COLOR_BTNHILIGHT) :
|
|
::GetSysColor(COLOR_BTNSHADOW));
|
|
pDC->Draw3dRect(rect,clrTopLeft,clrBottomRight);
|
|
|
|
rect.DeflateRect(1,1);
|
|
pDC->FillSolidRect(rect,::GetSysColor(COLOR_BTNFACE));
|
|
|
|
return rect;
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
void COXDropEdit<PARENTEDIT>::DrawButtonImage(CDC* pDC, CRect rect, BOOL bPressed)
|
|
{
|
|
ASSERT(pDC!=NULL);
|
|
|
|
int nOldBkMode=pDC->SetBkMode(TRANSPARENT);
|
|
COLORREF clrText=::GetSysColor(COLOR_WINDOWTEXT);
|
|
if(!IsWindowEnabled() || (GetStyle()&ES_READONLY))
|
|
clrText=::GetSysColor(COLOR_GRAYTEXT);
|
|
COLORREF clrOldText=pDC->SetTextColor(clrText);
|
|
|
|
if(bPressed)
|
|
rect.DeflateRect(1,1,0,0);
|
|
CString sText=_T("...");
|
|
pDC->DrawText(sText,rect,DT_CENTER|DT_BOTTOM|DT_SINGLELINE);
|
|
|
|
pDC->SetBkMode(nOldBkMode);
|
|
pDC->SetTextColor(clrOldText);
|
|
}
|
|
|
|
|
|
template<class PARENTEDIT>
|
|
BOOL COXDropEdit<PARENTEDIT>::HitButtonTest(CPoint ptTest)
|
|
{
|
|
ASSERT(::IsWindow(GetSafeHwnd()));
|
|
|
|
if(!IsButtonVisible())
|
|
return FALSE;
|
|
|
|
CRect rectButton=CalcButtonRect();
|
|
ClientToScreen(rectButton);
|
|
|
|
return rectButton.PtInRect(ptTest);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//{{AFX_INSERT_LOCATION}}
|
|
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
|
|
|
#endif // !defined(_OXDROPEDIT_H__)
|