add wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK and semi-automatic header resizing support

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57186 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-12-08 12:15:17 +00:00
parent 04a33b5031
commit 3bfaa5a7e4
8 changed files with 173 additions and 28 deletions

View File

@@ -68,9 +68,12 @@ private:
// return the horizontal start position of the given column
int GetColStart(unsigned int idx) const;
// refresh the given column [only]
// refresh the given column [only]; idx must be valid
void RefreshCol(unsigned int idx);
// refresh the given column if idx is valid
void RefreshColIfNotNone(unsigned int idx);
// refresh all the controls starting from (and including) the given one
void RefreshColsAfter(unsigned int idx);

View File

@@ -20,6 +20,7 @@
// notice that the classes in this header are defined in the core library even
// although currently they're only used by wxGrid which is in wxAdv because we
// plan to use it in wxListCtrl which is in core too in the future
class WXDLLIMPEXP_FWD_CORE wxHeaderCtrlEvent;
// ----------------------------------------------------------------------------
// constants
@@ -101,6 +102,15 @@ protected:
// information for the given column
virtual wxHeaderColumnBase& GetColumn(unsigned int idx) = 0;
// this method is called from the default EVT_HEADER_SEPARATOR_DCLICK
// handler to update the fitting column width of the given column, it
// should return true if the width was really updated
virtual bool UpdateColumnWidthToFit(unsigned int WXUNUSED(idx),
int WXUNUSED(widthTitle))
{
return false;
}
private:
// methods implementing our public API and defined in platform-specific
// implementations
@@ -112,6 +122,11 @@ private:
// this window doesn't look nice with the border so don't use it by default
virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
// event handlers
void OnSeparatorDClick(wxHeaderCtrlEvent& event);
DECLARE_EVENT_TABLE()
};
// ----------------------------------------------------------------------------
@@ -276,6 +291,8 @@ extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_DCLICK;
extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK;
extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_DCLICK;
extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK;
typedef void (wxEvtHandler::*wxHeaderCtrlEventFunction)(wxHeaderCtrlEvent&);
#define wxHeaderCtrlEventHandler(func) \
@@ -293,4 +310,6 @@ typedef void (wxEvtHandler::*wxHeaderCtrlEventFunction)(wxHeaderCtrlEvent&);
#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)
#define EVT_HEADER_SEPARATOR_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(SEPARATOR_DCLICK, id, fn)
#endif // _WX_HEADERCTRL_H_

View File

@@ -71,9 +71,13 @@ private:
enum Operation { Set, Insert };
void DoSetOrInsertItem(Operation oper, unsigned int idx);
// send an event of the given type for the given column, return true if it
// was processed
bool SendEvent(wxEventType evtType, 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);
bool SendClickEvent(bool dblclk, int button, unsigned int idx);
// the image list: initially NULL, created on demand

View File

@@ -63,6 +63,12 @@
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.
@event{EVT_HEADER_SEPARATOR_DCLICK(id, func)}
Separator to the right of the specified column was double clicked
(this action is commonly used to resize the column to fit its
contents width and the control provides UpdateColumnWidthToFit() method
to make implementing this easier).
@endEventTable
@library{wxcore}
@@ -170,6 +176,61 @@ protected:
SetColumnCount().
*/
virtual wxHeaderColumnBase& GetColumn(unsigned int idx) = 0;
/**
Method which may be implemented by the derived classes to allow double
clicking the column separator to resize the column to fit its contents.
When a separator is double clicked, the default handler of
EVT_HEADER_SEPARATOR_DCLICK event calls this function and refreshes the
column if it returns @true so to implement the resizing of the column
to fit its width on header double click you need to implement this
method using logic similar to this example:
@code
class MyHeaderCtrl : public wxHeaderColumnBase
{
public:
...
void SetWidth(int width) { m_width = width; }
virtual int GetWidth() const { return m_width; }
private:
int m_width;
};
class MyHeaderCtrl : public wxHeaderCtrl
{
public:
protected:
virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
{
return m_cols[idx];
}
virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle)
{
int widthContents = ... compute minimal width for column idx ...
m_cols[idx].SetWidth(wxMax(widthContents, widthTitle));
return true;
}
wxVector<MyHeaderColumn> m_cols;
};
@endcode
Base class version simply returns @false.
@param width
Contains minimal width needed to display the column header itself
and will usually be used as a starting point for the fitting width
calculation.
@return
@true to indicate that the column was resized, i.e. GetColumn() now
returns the new width value, and so must be refreshed or @false
meaning that the control didn't reach to the separator double click.
*/
virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle);
};

View File

@@ -45,6 +45,10 @@ const unsigned int wxNO_COLUMN = static_cast<unsigned>(-1);
extern WXDLLIMPEXP_DATA_CORE(const char) wxHeaderCtrlNameStr[] = "wxHeaderCtrl";
BEGIN_EVENT_TABLE(wxHeaderCtrlBase, wxControl)
EVT_HEADER_SEPARATOR_DCLICK(wxID_ANY, wxHeaderCtrlBase::OnSeparatorDClick)
END_EVENT_TABLE()
void wxHeaderCtrlBase::ScrollWindow(int dx,
int WXUNUSED_UNLESS_DEBUG(dy),
const wxRect * WXUNUSED_UNLESS_DEBUG(rect))
@@ -60,6 +64,19 @@ void wxHeaderCtrlBase::ScrollWindow(int dx,
DoScrollHorz(dx);
}
void wxHeaderCtrlBase::OnSeparatorDClick(wxHeaderCtrlEvent& event)
{
const unsigned col = event.GetColumn();
int w = wxWindowBase::GetTextExtent(GetColumn(col).GetTitle()).x;
w += 2*GetCharWidth(); // add some arbitrary margins around text
if ( !UpdateColumnWidthToFit(col, w) )
event.Skip();
else
UpdateColumn(col);
}
// ============================================================================
// wxHeaderCtrlSimple implementation
// ============================================================================
@@ -145,3 +162,5 @@ 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();
const wxEventType wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK = wxNewEventType();

View File

@@ -88,12 +88,25 @@ public:
wxDataViewCtrl *GetOwner() const
{ return static_cast<wxDataViewCtrl *>(GetParent()); }
private:
protected:
// implement/override wxHeaderCtrl functions by forwarding them to the main
// control
virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
{
return *(GetOwner()->GetColumn(idx));
}
virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle)
{
wxDataViewCtrl * const owner = GetOwner();
int widthContents = owner->GetBestColumnWidth(idx);
owner->GetColumn(idx)->SetWidth(wxMax(widthTitle, widthContents));
return true;
}
private:
bool SendEvent(wxEventType type, unsigned int n)
{
wxDataViewCtrl * const owner = GetOwner();

View File

@@ -213,7 +213,7 @@ void wxHeaderCtrl::RefreshColsAfter(unsigned int idx)
// wxHeaderCtrl event handlers
// ----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(wxHeaderCtrl, wxControl)
BEGIN_EVENT_TABLE(wxHeaderCtrl, wxHeaderCtrlBase)
EVT_PAINT(wxHeaderCtrl::OnPaint)
EVT_MOUSE_EVENTS(wxHeaderCtrl::OnMouse)
@@ -330,15 +330,24 @@ void wxHeaderCtrl::OnMouse(wxMouseEvent& mevent)
}
// determine the type of header event corresponding to this mouse event
wxEventType evtType;
const bool click = mevent.ButtonUp();
if ( click || mevent.ButtonDClick() )
wxEventType evtType = wxEVT_NULL;
const bool click = mevent.ButtonUp(),
dblclk = mevent.ButtonDClick();
if ( click || dblclk )
{
switch ( mevent.GetButton() )
{
case wxMOUSE_BTN_LEFT:
// treat left double clicks on separator specially
if ( onSeparator && dblclk )
{
evtType = wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK;
}
else // not double click on separator
{
evtType = click ? wxEVT_COMMAND_HEADER_CLICK
: wxEVT_COMMAND_HEADER_DCLICK;
}
break;
case wxMOUSE_BTN_RIGHT:
@@ -353,8 +362,12 @@ void wxHeaderCtrl::OnMouse(wxMouseEvent& mevent)
default:
// ignore clicks from other mouse buttons
return;
;
}
}
if ( evtType == wxEVT_NULL )
return;
wxHeaderCtrlEvent event(evtType, GetId());
event.SetEventObject(this);
@@ -363,6 +376,5 @@ void wxHeaderCtrl::OnMouse(wxMouseEvent& mevent)
if ( GetEventHandler()->ProcessEvent(event) )
mevent.Skip(false);
}
}
#endif // wxHAS_GENERIC_HEADERCTRL

View File

@@ -28,6 +28,9 @@
#endif // WX_PRECOMP
#include "wx/headerctrl.h"
#ifndef wxHAS_GENERIC_HEADERCTRL
#include "wx/imaglist.h"
#include "wx/msw/wrapcctl.h"
@@ -257,7 +260,16 @@ void wxHeaderCtrl::DoSetOrInsertItem(Operation oper, unsigned int idx)
// wxHeaderCtrl events
// ----------------------------------------------------------------------------
bool wxHeaderCtrl::SendClickEvent(bool dblclk, unsigned int idx, int button)
bool wxHeaderCtrl::SendEvent(wxEventType evtType, unsigned int idx)
{
wxHeaderCtrlEvent event(evtType, GetId());
event.SetEventObject(this);
event.SetColumn(idx);
return GetEventHandler()->ProcessEvent(event);
}
bool wxHeaderCtrl::SendClickEvent(bool dblclk, int button, unsigned int idx)
{
wxEventType evtType;
switch ( button )
@@ -282,24 +294,19 @@ bool wxHeaderCtrl::SendClickEvent(bool dblclk, unsigned int idx, int button)
return false;
}
wxHeaderCtrlEvent event(evtType, GetId());
event.SetEventObject(this);
event.SetColumn(idx);
return GetEventHandler()->ProcessEvent(event);
return SendEvent(evtType, idx);
}
bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{
NMHEADER * const nmhdr = (NMHEADER *)lParam;
switch ( nmhdr->hdr.code )
const int idx = nmhdr->iItem;
switch ( const UINT code = nmhdr->hdr.code )
{
case HDN_ITEMCLICK:
case HDN_ITEMDBLCLICK:
if ( SendClickEvent(nmhdr->hdr.code == HDN_ITEMDBLCLICK,
nmhdr->iItem,
nmhdr->iButton) )
if ( SendClickEvent(code == HDN_ITEMDBLCLICK, nmhdr->iButton, idx) )
return true;
break;
@@ -313,13 +320,20 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
const int col = wxMSWGetColumnClicked(&nmhdr->hdr, &pt);
if ( col != wxNOT_FOUND )
{
if ( SendClickEvent(nmhdr->hdr.code == NM_RDBLCLK, col, 1) )
if ( SendClickEvent(code == NM_RDBLCLK, 1, col) )
return true;
}
//else: ignore clicks outside any column
}
break;
case HDN_DIVIDERDBLCLICK:
if ( SendEvent(wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK, idx) )
return true;
break;
}
return wxHeaderCtrlBase::MSWOnNotify(idCtrl, lParam, result);
}
#endif // wxHAS_GENERIC_HEADERCTRL