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 // return the horizontal start position of the given column
int GetColStart(unsigned int idx) const; 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); 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 // refresh all the controls starting from (and including) the given one
void RefreshColsAfter(unsigned int idx); 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 // 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 // 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 // plan to use it in wxListCtrl which is in core too in the future
class WXDLLIMPEXP_FWD_CORE wxHeaderCtrlEvent;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// constants // constants
@@ -101,6 +102,15 @@ protected:
// information for the given column // information for the given column
virtual wxHeaderColumnBase& GetColumn(unsigned int idx) = 0; 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: private:
// methods implementing our public API and defined in platform-specific // methods implementing our public API and defined in platform-specific
// implementations // implementations
@@ -112,6 +122,11 @@ private:
// this window doesn't look nice with the border so don't use it by default // this window doesn't look nice with the border so don't use it by default
virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; } 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_RIGHT_DCLICK;
extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_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&); typedef void (wxEvtHandler::*wxHeaderCtrlEventFunction)(wxHeaderCtrlEvent&);
#define wxHeaderCtrlEventHandler(func) \ #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_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_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_ #endif // _WX_HEADERCTRL_H_

View File

@@ -71,9 +71,13 @@ private:
enum Operation { Set, Insert }; enum Operation { Set, Insert };
void DoSetOrInsertItem(Operation oper, unsigned int idx); 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 // send a click or double click event (depending on dblclk value) for the
// click with the given button on the given item // 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 // the image list: initially NULL, created on demand

View File

@@ -63,6 +63,12 @@
A column heading was right double clicked. A column heading was right double clicked.
@event{EVT_HEADER_MIDDLE_DCLICK(id, func)} @event{EVT_HEADER_MIDDLE_DCLICK(id, func)}
A column heading was double clicked with the middle mouse button. 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 @endEventTable
@library{wxcore} @library{wxcore}
@@ -170,6 +176,61 @@ protected:
SetColumnCount(). SetColumnCount().
*/ */
virtual wxHeaderColumnBase& GetColumn(unsigned int idx) = 0; 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"; 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, void wxHeaderCtrlBase::ScrollWindow(int dx,
int WXUNUSED_UNLESS_DEBUG(dy), int WXUNUSED_UNLESS_DEBUG(dy),
const wxRect * WXUNUSED_UNLESS_DEBUG(rect)) const wxRect * WXUNUSED_UNLESS_DEBUG(rect))
@@ -60,6 +64,19 @@ void wxHeaderCtrlBase::ScrollWindow(int dx,
DoScrollHorz(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 // 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_DCLICK = wxNewEventType();
const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK = wxNewEventType(); const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK = wxNewEventType();
const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_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 wxDataViewCtrl *GetOwner() const
{ return static_cast<wxDataViewCtrl *>(GetParent()); } { return static_cast<wxDataViewCtrl *>(GetParent()); }
private: protected:
// implement/override wxHeaderCtrl functions by forwarding them to the main
// control
virtual wxHeaderColumnBase& GetColumn(unsigned int idx) virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
{ {
return *(GetOwner()->GetColumn(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) bool SendEvent(wxEventType type, unsigned int n)
{ {
wxDataViewCtrl * const owner = GetOwner(); wxDataViewCtrl * const owner = GetOwner();

View File

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

View File

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