implement click events in wxHeaderCtrl

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57178 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-12-08 00:57:53 +00:00
parent ef52f19e6a
commit fa3d4aaf0f
8 changed files with 328 additions and 12 deletions

View File

@@ -74,6 +74,14 @@ private:
// refresh all the controls starting from (and including) the given one
void RefreshColsAfter(unsigned int idx);
// return the column at the given position or -1 if it is beyond the
// rightmost column and put true into onSeparator output parameter if the
// position is near the divider at the right end of this column (notice
// that this means that we return column 0 even if the position is over
// column 1 but close enough to the divider separating it from column 0)
int FindColumnAtPos(int x, bool& onSeparator) const;
// number of columns in the control currently
unsigned int m_numColumns;

View File

@@ -120,7 +120,7 @@ private:
// control, see wxHeaderCtrlSimple for a standalone version
// ----------------------------------------------------------------------------
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
#if 0// defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
#include "wx/msw/headerctrl.h"
#else
#define wxHAS_GENERIC_HEADERCTRL
@@ -236,4 +236,61 @@ private:
DECLARE_NO_COPY_CLASS(wxHeaderCtrlSimple)
};
// ----------------------------------------------------------------------------
// wxHeaderCtrl events
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_CORE wxHeaderCtrlEvent : public wxNotifyEvent
{
public:
wxHeaderCtrlEvent(wxEventType commandType = wxEVT_NULL, int winid = 0)
: wxNotifyEvent(commandType, winid)
{
}
wxHeaderCtrlEvent(const wxHeaderCtrlEvent& event)
: wxNotifyEvent(event),
m_col(event.m_col)
{
}
int GetColumn() const { return m_col; }
void SetColumn(int col) { m_col = col; }
virtual wxEvent *Clone() const { return new wxHeaderCtrlEvent(*this); }
protected:
// the column affected by the event
int m_col;
private:
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxHeaderCtrlEvent)
};
extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_CLICK;
extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_RIGHT_CLICK;
extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_CLICK;
extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_DCLICK;
extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK;
extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_DCLICK;
typedef void (wxEvtHandler::*wxHeaderCtrlEventFunction)(wxHeaderCtrlEvent&);
#define wxHeaderCtrlEventHandler(func) \
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent( \
wxHeaderCtrlEventFunction, &func)
#define wx__DECLARE_HEADER_EVT(evt, id, fn) \
wx__DECLARE_EVT1(wxEVT_COMMAND_HEADER_ ## evt, id, wxHeaderCtrlEventHandler(fn))
#define EVT_HEADER_CLICK(id, fn) wx__DECLARE_HEADER_EVT(CLICK, id, fn)
#define EVT_HEADER_RIGHT_CLICK(id, fn) wx__DECLARE_HEADER_EVT(RIGHT_CLICK, id, fn)
#define EVT_HEADER_MIDDLE_CLICK(id, fn) wx__DECLARE_HEADER_EVT(MIDDLE_CLICK, id, fn)
#define EVT_HEADER_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(DCLICK, id, fn)
#define EVT_HEADER_RIGHT_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(RIGHT_DCLICK, id, fn)
#define EVT_HEADER_MIDDLE_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(MIDDLE_DCLICK, id, fn)
#endif // _WX_HEADERCTRL_H_

View File

@@ -60,6 +60,7 @@ private:
// override MSW-specific methods needed for new control
virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const;
virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
// common part of all ctors
void Init();
@@ -70,6 +71,10 @@ private:
enum Operation { Set, Insert };
void DoSetOrInsertItem(Operation oper, unsigned int idx);
// send a click or double click event (depending on dblclk value) for the
// click with the given button on the given item
bool SendClickEvent(bool dblclk, unsigned int idx, int button);
// the image list: initially NULL, created on demand
wxImageList *m_imageList;

View File

@@ -49,9 +49,20 @@
wxHD_DRAGDROP.
@endStyleTable
@beginEventTable{wxHeaderEvent}
@beginEventTable{wxHeaderCtrlEvent}
@event{EVT_HEADER_CLICK(id, func)}
A column heading was clicked.
@event{EVT_HEADER_RIGHT_CLICK(id, func)}
A column heading was right clicked.
@event{EVT_HEADER_MIDDLE_CLICK(id, func)}
A column heading was clicked with the middle mouse button.
@event{EVT_HEADER_DCLICK(id, func)}
A column heading was double clicked.
@event{EVT_HEADER_RIGHT_DCLICK(id, func)}
A column heading was right double clicked.
@event{EVT_HEADER_MIDDLE_DCLICK(id, func)}
A column heading was double clicked with the middle mouse button.
@endEventTable
@library{wxcore}
@@ -285,3 +296,22 @@ public:
*/
void RemoveSortIndicator(unsigned int idx);
};
/**
@class wxHeaderCtrlEvent
Event class representing the events generated by wxHeaderCtrl.
@library{wxcore}
@category{ctrl}
@see wxHeaderCtrl
*/
class wxHeaderCtrlEvent : public wxNotifyEvent
{
public:
/**
Return the index of the column affected by this event.
*/
int GetColumn() const;
};

View File

@@ -132,3 +132,16 @@ void wxHeaderCtrlSimple::RemoveSortIndicator()
}
}
// ============================================================================
// wxHeaderCtrlEvent implementation
// ============================================================================
IMPLEMENT_DYNAMIC_CLASS(wxHeaderCtrlEvent, wxNotifyEvent)
const wxEventType wxEVT_COMMAND_HEADER_CLICK = wxNewEventType();
const wxEventType wxEVT_COMMAND_HEADER_RIGHT_CLICK = wxNewEventType();
const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_CLICK = wxNewEventType();
const wxEventType wxEVT_COMMAND_HEADER_DCLICK = wxNewEventType();
const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK = wxNewEventType();
const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_DCLICK = wxNewEventType();

View File

@@ -67,16 +67,16 @@ static const int EXPANDER_OFFSET = 4;
static const int EXPANDER_OFFSET = 1;
#endif
//-----------------------------------------------------------------------------
// wxDataViewHeaderWindow
//-----------------------------------------------------------------------------
//Below is the compare stuff
//For the generic implements, both the leaf nodes and the nodes are sorted for fast search when needed
static wxDataViewModel * g_model;
static int g_column = -2;
static bool g_asending = true;
//-----------------------------------------------------------------------------
// wxDataViewHeaderWindow
//-----------------------------------------------------------------------------
class wxDataViewHeaderWindow : public wxHeaderCtrl
{
public:
@@ -88,16 +88,50 @@ public:
wxDataViewCtrl *GetOwner() const
{ return static_cast<wxDataViewCtrl *>(GetParent()); }
protected:
private:
virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
{
return *(GetOwner()->GetColumn(idx));
}
private:
bool SendEvent(wxEventType type, unsigned int n)
{
wxDataViewCtrl * const owner = GetOwner();
wxDataViewEvent event(type, owner->GetId());
event.SetEventObject(owner);
event.SetColumn(n);
event.SetDataViewColumn(owner->GetColumn(n));
event.SetModel(owner->GetModel());
// for events created by wxDataViewHeaderWindow the
// row / value fields are not valid
return owner->GetEventHandler()->ProcessEvent(event);
}
void OnClick(wxHeaderCtrlEvent& event)
{
if ( !SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK,
event.GetColumn()) )
event.Skip();
}
void OnRClick(wxHeaderCtrlEvent& event)
{
if ( !SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
event.GetColumn()) )
event.Skip();
}
DECLARE_EVENT_TABLE()
DECLARE_NO_COPY_CLASS(wxDataViewHeaderWindow)
};
BEGIN_EVENT_TABLE(wxDataViewHeaderWindow, wxHeaderCtrl)
EVT_HEADER_CLICK(wxID_ANY, wxDataViewHeaderWindow::OnClick)
EVT_HEADER_RIGHT_CLICK(wxID_ANY, wxDataViewHeaderWindow::OnRClick)
END_EVENT_TABLE()
//-----------------------------------------------------------------------------
// wxDataViewRenameTimer
//-----------------------------------------------------------------------------

View File

@@ -145,6 +145,41 @@ int wxHeaderCtrl::GetColStart(unsigned int idx) const
return pos;
}
int wxHeaderCtrl::FindColumnAtPos(int x, bool& onSeparator) const
{
wxHeaderCtrl * const self = const_cast<wxHeaderCtrl *>(this);
int pos = 0;
const unsigned count = GetColumnCount();
for ( unsigned n = 0; n < count; n++ )
{
const wxHeaderColumnBase& col = self->GetColumn(n);
if ( col.IsHidden() )
continue;
pos += col.GetWidth();
// if the column is resizeable, check if we're approximatively over the
// line separating it from the next column
//
// TODO: don't hardcode sensitivity
if ( col.IsResizeable() && abs(x - pos) < 8 )
{
onSeparator = true;
return n;
}
// inside this column?
if ( x < pos )
{
onSeparator = false;
return n;
}
}
return COL_NONE;
}
// ----------------------------------------------------------------------------
// wxHeaderCtrl repainting
// ----------------------------------------------------------------------------
@@ -242,9 +277,70 @@ void wxHeaderCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
}
}
void wxHeaderCtrl::OnMouse(wxMouseEvent& event)
void wxHeaderCtrl::OnMouse(wxMouseEvent& mevent)
{
event.Skip();
mevent.Skip();
// find if the event is over a column at all
bool onSeparator;
const unsigned col = FindColumnAtPos(mevent.GetX(), onSeparator);
if ( col == COL_NONE )
return;
// update mouse cursor as it moves around
if ( mevent.Moving() )
{
SetCursor(onSeparator ? wxCursor(wxCURSOR_SIZEWE) : wxNullCursor);
return;
}
if ( mevent.LeftDown() )
{
// TODO
if ( onSeparator )
// resize column
;
else
// drag column
;
return;
}
// determine the type of header event corresponding to this mouse event
wxEventType evtType;
const bool click = mevent.ButtonUp();
if ( click || mevent.ButtonDClick() )
{
switch ( mevent.GetButton() )
{
case wxMOUSE_BTN_LEFT:
evtType = click ? wxEVT_COMMAND_HEADER_CLICK
: wxEVT_COMMAND_HEADER_DCLICK;
break;
case wxMOUSE_BTN_RIGHT:
evtType = click ? wxEVT_COMMAND_HEADER_RIGHT_CLICK
: wxEVT_COMMAND_HEADER_RIGHT_DCLICK;
break;
case wxMOUSE_BTN_MIDDLE:
evtType = click ? wxEVT_COMMAND_HEADER_MIDDLE_CLICK
: wxEVT_COMMAND_HEADER_MIDDLE_DCLICK;
break;
default:
// ignore clicks from other mouse buttons
return;
}
wxHeaderCtrlEvent event(evtType, GetId());
event.SetEventObject(this);
event.SetColumn(col);
if ( GetEventHandler()->ProcessEvent(event) )
mevent.Skip(false);
}
}
#endif // wxHAS_GENERIC_HEADERCTRL

View File

@@ -33,6 +33,9 @@
#include "wx/msw/wrapcctl.h"
#include "wx/msw/private.h"
// from src/msw/listctrl.cpp
extern int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick);
// ============================================================================
// wxHeaderCtrl implementation
// ============================================================================
@@ -250,3 +253,73 @@ void wxHeaderCtrl::DoSetOrInsertItem(Operation oper, unsigned int idx)
}
}
// ----------------------------------------------------------------------------
// wxHeaderCtrl events
// ----------------------------------------------------------------------------
bool wxHeaderCtrl::SendClickEvent(bool dblclk, unsigned int idx, int button)
{
wxEventType evtType;
switch ( button )
{
case 0:
evtType = dblclk ? wxEVT_COMMAND_HEADER_DCLICK
: wxEVT_COMMAND_HEADER_CLICK;
break;
case 1:
evtType = dblclk ? wxEVT_COMMAND_HEADER_RIGHT_DCLICK
: wxEVT_COMMAND_HEADER_RIGHT_CLICK;
break;
case 2:
evtType = dblclk ? wxEVT_COMMAND_HEADER_MIDDLE_DCLICK
: wxEVT_COMMAND_HEADER_MIDDLE_CLICK;
break;
default:
wxFAIL_MSG( wxS("unexpected event type") );
return false;
}
wxHeaderCtrlEvent event(evtType, GetId());
event.SetEventObject(this);
event.SetColumn(idx);
return GetEventHandler()->ProcessEvent(event);
}
bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{
NMHEADER * const nmhdr = (NMHEADER *)lParam;
switch ( nmhdr->hdr.code )
{
case HDN_ITEMCLICK:
case HDN_ITEMDBLCLICK:
if ( SendClickEvent(nmhdr->hdr.code == HDN_ITEMDBLCLICK,
nmhdr->iItem,
nmhdr->iButton) )
return true;
break;
// although we should get the notifications about the right clicks
// via HDN_ITEM[DBL]CLICK too according to MSDN this simply doesn't
// happen in practice on any Windows system up to 2003
case NM_RCLICK:
case NM_RDBLCLK:
{
POINT pt;
const int col = wxMSWGetColumnClicked(&nmhdr->hdr, &pt);
if ( col != wxNOT_FOUND )
{
if ( SendClickEvent(nmhdr->hdr.code == NM_RDBLCLK, col, 1) )
return true;
}
//else: ignore clicks outside any column
}
break;
}
return wxHeaderCtrlBase::MSWOnNotify(idCtrl, lParam, result);
}