Merge branch 'grid-fixes'

Fixes for wxGrid when using native header control.

Closes https://github.com/wxWidgets/wxWidgets/pull/1529
This commit is contained in:
Vadim Zeitlin
2019-09-05 23:36:50 +02:00
5 changed files with 423 additions and 150 deletions

View File

@@ -95,7 +95,7 @@ public:
virtual wxString GetTitle() const wxOVERRIDE { return m_grid->GetColLabelValue(m_col); } virtual wxString GetTitle() const wxOVERRIDE { return m_grid->GetColLabelValue(m_col); }
virtual wxBitmap GetBitmap() const wxOVERRIDE { return wxNullBitmap; } virtual wxBitmap GetBitmap() const wxOVERRIDE { return wxNullBitmap; }
virtual int GetWidth() const wxOVERRIDE { return m_grid->GetColSize(m_col); } virtual int GetWidth() const wxOVERRIDE { return m_grid->GetColSize(m_col); }
virtual int GetMinWidth() const wxOVERRIDE { return 0; } virtual int GetMinWidth() const wxOVERRIDE { return m_grid->GetColMinimalAcceptableWidth(); }
virtual wxAlignment GetAlignment() const wxOVERRIDE virtual wxAlignment GetAlignment() const wxOVERRIDE
{ {
int horz, int horz,

View File

@@ -10,15 +10,15 @@
#ifndef _WX_MSW_HEADERCTRL_H_ #ifndef _WX_MSW_HEADERCTRL_H_
#define _WX_MSW_HEADERCTRL_H_ #define _WX_MSW_HEADERCTRL_H_
class WXDLLIMPEXP_FWD_CORE wxImageList; #include "wx/compositewin.h"
class wxMSWHeaderCtrlCustomDraw; class wxMSWHeaderCtrl;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxHeaderCtrl // wxHeaderCtrl
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class WXDLLIMPEXP_CORE wxHeaderCtrl : public wxHeaderCtrlBase class WXDLLIMPEXP_CORE wxHeaderCtrl : public wxCompositeWindow<wxHeaderCtrlBase>
{ {
public: public:
wxHeaderCtrl() wxHeaderCtrl()
@@ -45,22 +45,15 @@ public:
long style = wxHD_DEFAULT_STYLE, long style = wxHD_DEFAULT_STYLE,
const wxString& name = wxHeaderCtrlNameStr); const wxString& name = wxHeaderCtrlNameStr);
virtual ~wxHeaderCtrl(); // Window style handling.
virtual void SetWindowStyleFlag(long style) wxOVERRIDE;
// Override to implement colours support via custom drawing.
virtual bool SetBackgroundColour(const wxColour& colour) wxOVERRIDE;
virtual bool SetForegroundColour(const wxColour& colour) wxOVERRIDE;
virtual bool SetFont(const wxFont& font) wxOVERRIDE;
protected: protected:
// override wxWindow methods which must be implemented by a new control // Override wxWindow methods which must be implemented by a new control.
virtual wxSize DoGetBestSize() const wxOVERRIDE; virtual wxSize DoGetBestSize() const wxOVERRIDE;
virtual void DoSetSize(int x, int y,
int width, int height,
int sizeFlags = wxSIZE_AUTO) wxOVERRIDE;
private: private:
// implement base class pure virtuals // Implement base class pure virtuals.
virtual void DoSetCount(unsigned int count) wxOVERRIDE; virtual void DoSetCount(unsigned int count) wxOVERRIDE;
virtual unsigned int DoGetCount() const wxOVERRIDE; virtual unsigned int DoGetCount() const wxOVERRIDE;
virtual void DoUpdate(unsigned int idx) wxOVERRIDE; virtual void DoUpdate(unsigned int idx) wxOVERRIDE;
@@ -70,81 +63,22 @@ private:
virtual void DoSetColumnsOrder(const wxArrayInt& order) wxOVERRIDE; virtual void DoSetColumnsOrder(const wxArrayInt& order) wxOVERRIDE;
virtual wxArrayInt DoGetColumnsOrder() const wxOVERRIDE; virtual wxArrayInt DoGetColumnsOrder() const wxOVERRIDE;
// override MSW-specific methods needed for new control // Pure virtual method inherited from wxCompositeWindow.
virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const wxOVERRIDE; virtual wxWindowList GetCompositeWindowParts() const wxOVERRIDE;
virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wxOVERRIDE;
// common part of all ctors // Common part of all ctors.
void Init(); void Init();
// wrapper around Header_InsertItem(): insert the item using information // Events.
// from the given column at the given index void OnSize(wxSizeEvent& event);
void DoInsertItem(const wxHeaderColumn& col, unsigned int idx);
// get the number of currently visible items: this is also the total number // Style flag helper function.
// of items contained in the native control long ApplyHeaderReorderFlagToStyle(long style);
int GetShownColumnsCount() const;
// due to the discrepancy for the hidden columns which we know about but
// the native control does not, there can be a difference between the
// column indices we use and the ones used by the native control; these
// functions translate between them
//
// notice that MSWToNativeIdx() shouldn't be called for hidden columns and
// MSWFromNativeIdx() always returns an index of a visible column
int MSWToNativeIdx(int idx);
int MSWFromNativeIdx(int item);
// this is the same as above but for order, not index
int MSWToNativeOrder(int order);
int MSWFromNativeOrder(int order);
// get the event type corresponding to a click or double click event
// (depending on dblclk value) with the specified (using MSW convention)
// mouse button
wxEventType GetClickEventType(bool dblclk, int button);
// allocate m_customDraw if we need it or free it if it no longer is,
// return the pointer which can be used to update it if it's non-null
wxMSWHeaderCtrlCustomDraw* GetCustomDraw();
// the number of columns in the control, including the hidden ones (not // The native header control.
// taken into account by the native control, see comment in DoGetCount()) wxMSWHeaderCtrl* m_nativeControl;
unsigned int m_numColumns; friend class wxMSWHeaderCtrl;
// this is a lookup table allowing us to check whether the column with the
// given index is currently shown in the native control, in which case the
// value of this array element with this index is 0, or hidden
//
// notice that this may be different from GetColumn(idx).IsHidden() and in
// fact we need this array precisely because it will be different from it
// in DoUpdate() when the column hidden flag gets toggled and we need it to
// handle this transition correctly
wxArrayInt m_isHidden;
// the order of our columns: this array contains the index of the column
// shown at the position n as the n-th element
//
// this is necessary only to handle the hidden columns: the native control
// doesn't know about them and so we can't use Header_GetOrderArray()
wxArrayInt m_colIndices;
// the image list: initially NULL, created on demand
wxImageList *m_imageList;
// the offset of the window used to emulate scrolling it
int m_scrollOffset;
// actual column we are dragging or -1 if not dragging anything
int m_colBeingDragged;
// a column is currently being resized
bool m_isColBeingResized;
// the custom draw helper: initially NULL, created on demand, use
// GetCustomDraw() to do it
wxMSWHeaderCtrlCustomDraw *m_customDraw;
wxDECLARE_NO_COPY_CLASS(wxHeaderCtrl); wxDECLARE_NO_COPY_CLASS(wxHeaderCtrl);
}; };

View File

@@ -3687,6 +3687,7 @@ void wxGrid::DoUpdateResizeColWidth(int w)
{ {
wxPoint pt(GetColLeft(m_dragRowOrCol) + w, 0); wxPoint pt(GetColLeft(m_dragRowOrCol) + w, 0);
pt = CalcGridWindowScrolledPosition(pt, m_gridWin);
DrawGridDragLine(pt, wxGridColumnOperations(), m_gridWin); DrawGridDragLine(pt, wxGridColumnOperations(), m_gridWin);
} }

View File

@@ -82,15 +82,141 @@ private:
} }
}; };
// ----------------------------------------------------------------------------
// wxMSWHeaderCtrl: the native header control
// ----------------------------------------------------------------------------
class wxMSWHeaderCtrl : public wxControl
{
public:
explicit wxMSWHeaderCtrl(wxHeaderCtrl& header) :
m_header(header)
{
Init();
}
bool Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name);
virtual ~wxMSWHeaderCtrl();
// Override to implement colours support via custom drawing.
virtual bool SetBackgroundColour(const wxColour& colour) wxOVERRIDE;
virtual bool SetForegroundColour(const wxColour& colour) wxOVERRIDE;
virtual bool SetFont(const wxFont& font) wxOVERRIDE;
// The implementation of wxHeaderCtrlBase virtual functions
void SetCount(unsigned int count);
unsigned int GetCount() const;
void UpdateHeader(unsigned int idx);
void ScrollHorz(int dx);
void SetColumnsOrder(const wxArrayInt& order);
wxArrayInt GetColumnsOrder() const;
protected:
// override wxWindow methods which must be implemented by a new control
virtual wxSize DoGetBestSize() const wxOVERRIDE;
virtual void DoSetSize(int x, int y,
int width, int height,
int sizeFlags = wxSIZE_AUTO) wxOVERRIDE;
private:
// override MSW-specific methods needed for new control
virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const wxOVERRIDE;
virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wxOVERRIDE;
// common part of all ctors
void Init();
// wrapper around Header_InsertItem(): insert the item using information
// from the given column at the given index
void DoInsertItem(const wxHeaderColumn& col, unsigned int idx);
// get the number of currently visible items: this is also the total number
// of items contained in the native control
int GetShownColumnsCount() const;
// due to the discrepancy for the hidden columns which we know about but
// the native control does not, there can be a difference between the
// column indices we use and the ones used by the native control; these
// functions translate between them
//
// notice that MSWToNativeIdx() shouldn't be called for hidden columns and
// MSWFromNativeIdx() always returns an index of a visible column
int MSWToNativeIdx(int idx);
int MSWFromNativeIdx(int item);
// this is the same as above but for order, not index
int MSWToNativeOrder(int order);
int MSWFromNativeOrder(int order);
// get the event type corresponding to a click or double click event
// (depending on dblclk value) with the specified (using MSW convention)
// mouse button
wxEventType GetClickEventType(bool dblclk, int button);
// allocate m_customDraw if we need it or free it if it no longer is,
// return the pointer which can be used to update it if it's non-null
wxMSWHeaderCtrlCustomDraw* GetCustomDraw();
// the real wxHeaderCtrl control
wxHeaderCtrl &m_header;
// the number of columns in the control, including the hidden ones (not
// taken into account by the native control, see comment in DoGetCount())
unsigned int m_numColumns;
// this is a lookup table allowing us to check whether the column with the
// given index is currently shown in the native control, in which case the
// value of this array element with this index is 0, or hidden
//
// notice that this may be different from GetColumn(idx).IsHidden() and in
// fact we need this array precisely because it will be different from it
// in DoUpdate() when the column hidden flag gets toggled and we need it to
// handle this transition correctly
wxArrayInt m_isHidden;
// the order of our columns: this array contains the index of the column
// shown at the position n as the n-th element
//
// this is necessary only to handle the hidden columns: the native control
// doesn't know about them and so we can't use Header_GetOrderArray()
wxArrayInt m_colIndices;
// the image list: initially NULL, created on demand
wxImageList *m_imageList;
// the offset of the window used to emulate scrolling it
int m_scrollOffset;
// actual column we are dragging or -1 if not dragging anything
int m_colBeingDragged;
// a column is currently being resized
bool m_isColBeingResized;
// the custom draw helper: initially NULL, created on demand, use
// GetCustomDraw() to do it
wxMSWHeaderCtrlCustomDraw *m_customDraw;
};
// ============================================================================ // ============================================================================
// wxHeaderCtrl implementation // wxMSWHeaderCtrl implementation
// ============================================================================ // ============================================================================
extern WXDLLIMPEXP_DATA_CORE(const char) wxMSWHeaderCtrlNameStr[] = "wxMSWHeaderCtrl";
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxHeaderCtrl construction/destruction // wxMSWHeaderCtrl construction/destruction
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void wxHeaderCtrl::Init() void wxMSWHeaderCtrl::Init()
{ {
m_numColumns = 0; m_numColumns = 0;
m_imageList = NULL; m_imageList = NULL;
@@ -100,12 +226,12 @@ void wxHeaderCtrl::Init()
m_customDraw = NULL; m_customDraw = NULL;
} }
bool wxHeaderCtrl::Create(wxWindow *parent, bool wxMSWHeaderCtrl::Create(wxWindow *parent,
wxWindowID id, wxWindowID id,
const wxPoint& pos, const wxPoint& pos,
const wxSize& size, const wxSize& size,
long style, long style,
const wxString& name) const wxString& name)
{ {
// notice that we don't need InitCommonControlsEx(ICC_LISTVIEW_CLASSES) // notice that we don't need InitCommonControlsEx(ICC_LISTVIEW_CLASSES)
// here as we already call InitCommonControls() in wxApp initialization // here as we already call InitCommonControls() in wxApp initialization
@@ -130,7 +256,7 @@ bool wxHeaderCtrl::Create(wxWindow *parent,
return true; return true;
} }
WXDWORD wxHeaderCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const WXDWORD wxMSWHeaderCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
{ {
WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle); WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
@@ -147,25 +273,25 @@ WXDWORD wxHeaderCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
return msStyle; return msStyle;
} }
wxHeaderCtrl::~wxHeaderCtrl() wxMSWHeaderCtrl::~wxMSWHeaderCtrl()
{ {
delete m_imageList; delete m_imageList;
delete m_customDraw; delete m_customDraw;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxHeaderCtrl scrolling // wxMSWHeaderCtrl scrolling
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void wxHeaderCtrl::DoSetSize(int x, int y, void wxMSWHeaderCtrl::DoSetSize(int x, int y,
int w, int h, int w, int h,
int sizeFlags) int sizeFlags)
{ {
wxHeaderCtrlBase::DoSetSize(x + m_scrollOffset, y, w - m_scrollOffset, h, wxControl::DoSetSize(x + m_scrollOffset, y, w - m_scrollOffset, h,
sizeFlags); sizeFlags & wxSIZE_FORCE);
} }
void wxHeaderCtrl::DoScrollHorz(int dx) void wxMSWHeaderCtrl::ScrollHorz(int dx)
{ {
// as the native control doesn't support offsetting its contents, we use a // as the native control doesn't support offsetting its contents, we use a
// hack here to make it appear correctly when the parent is scrolled: // hack here to make it appear correctly when the parent is scrolled:
@@ -175,18 +301,18 @@ void wxHeaderCtrl::DoScrollHorz(int dx)
// for it (notice that dx is negative when scrolling to the right) // for it (notice that dx is negative when scrolling to the right)
m_scrollOffset += dx; m_scrollOffset += dx;
wxHeaderCtrlBase::DoSetSize(GetPosition().x + dx, -1, wxControl::DoSetSize(GetPosition().x + dx, -1,
GetSize().x - dx, -1, GetSize().x - dx, -1,
wxSIZE_USE_EXISTING); wxSIZE_USE_EXISTING);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxHeaderCtrl geometry calculation // wxMSWHeaderCtrl geometry calculation
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxSize wxHeaderCtrl::DoGetBestSize() const wxSize wxMSWHeaderCtrl::DoGetBestSize() const
{ {
RECT rc = wxGetClientRect(GetHwndOf(GetParent())); RECT rc = wxGetClientRect(GetHwndOf(m_header.GetParent()));
WINDOWPOS wpos; WINDOWPOS wpos;
HDLAYOUT layout = { &rc, &wpos }; HDLAYOUT layout = { &rc, &wpos };
if ( !Header_Layout(GetHwnd(), &layout) ) if ( !Header_Layout(GetHwnd(), &layout) )
@@ -199,10 +325,10 @@ wxSize wxHeaderCtrl::DoGetBestSize() const
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxHeaderCtrl columns managements // wxMSWHeaderCtrl columns managements
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
unsigned int wxHeaderCtrl::DoGetCount() const unsigned int wxMSWHeaderCtrl::GetCount() const
{ {
// we can't use Header_GetItemCount() here because it doesn't take the // we can't use Header_GetItemCount() here because it doesn't take the
// hidden columns into account and we can't find the hidden columns after // hidden columns into account and we can't find the hidden columns after
@@ -211,7 +337,7 @@ unsigned int wxHeaderCtrl::DoGetCount() const
return m_numColumns; return m_numColumns;
} }
int wxHeaderCtrl::GetShownColumnsCount() const int wxMSWHeaderCtrl::GetShownColumnsCount() const
{ {
const int numItems = Header_GetItemCount(GetHwnd()); const int numItems = Header_GetItemCount(GetHwnd());
@@ -221,7 +347,7 @@ int wxHeaderCtrl::GetShownColumnsCount() const
return numItems; return numItems;
} }
void wxHeaderCtrl::DoSetCount(unsigned int count) void wxMSWHeaderCtrl::SetCount(unsigned int count)
{ {
unsigned n; unsigned n;
@@ -236,14 +362,14 @@ void wxHeaderCtrl::DoSetCount(unsigned int count)
} }
// update the column indices order array before changing m_numColumns // update the column indices order array before changing m_numColumns
DoResizeColumnIndices(m_colIndices, count); m_header.DoResizeColumnIndices(m_colIndices, count);
// and add the new ones // and add the new ones
m_numColumns = count; m_numColumns = count;
m_isHidden.resize(m_numColumns); m_isHidden.resize(m_numColumns);
for ( n = 0; n < count; n++ ) for ( n = 0; n < count; n++ )
{ {
const wxHeaderColumn& col = GetColumn(n); const wxHeaderColumn& col = m_header.GetColumn(n);
if ( col.IsShown() ) if ( col.IsShown() )
{ {
m_isHidden[n] = false; m_isHidden[n] = false;
@@ -257,7 +383,7 @@ void wxHeaderCtrl::DoSetCount(unsigned int count)
} }
} }
void wxHeaderCtrl::DoUpdate(unsigned int idx) void wxMSWHeaderCtrl::UpdateHeader(unsigned int idx)
{ {
// the native control does provide Header_SetItem() but it's inconvenient // the native control does provide Header_SetItem() but it's inconvenient
// to use it because it sends HDN_ITEMCHANGING messages and we'd have to // to use it because it sends HDN_ITEMCHANGING messages and we'd have to
@@ -265,7 +391,7 @@ void wxHeaderCtrl::DoUpdate(unsigned int idx)
// more complicated as we'd have to reset the old values as well as setting // more complicated as we'd have to reset the old values as well as setting
// the new ones -- so instead just recreate the column // the new ones -- so instead just recreate the column
const wxHeaderColumn& col = GetColumn(idx); const wxHeaderColumn& col = m_header.GetColumn(idx);
if ( col.IsHidden() ) if ( col.IsHidden() )
{ {
// column is hidden now // column is hidden now
@@ -296,7 +422,7 @@ void wxHeaderCtrl::DoUpdate(unsigned int idx)
} }
} }
void wxHeaderCtrl::DoInsertItem(const wxHeaderColumn& col, unsigned int idx) void wxMSWHeaderCtrl::DoInsertItem(const wxHeaderColumn& col, unsigned int idx)
{ {
wxASSERT_MSG( !col.IsHidden(), "should only be called for shown columns" ); wxASSERT_MSG( !col.IsHidden(), "should only be called for shown columns" );
@@ -389,9 +515,9 @@ void wxHeaderCtrl::DoInsertItem(const wxHeaderColumn& col, unsigned int idx)
// be implemented, it is per-control rather than per-column in the native // be implemented, it is per-control rather than per-column in the native
// control. Enable resizing cursor if at least one column is resizeble. // control. Enable resizing cursor if at least one column is resizeble.
bool hasResizableColumns = false; bool hasResizableColumns = false;
for ( unsigned n = 0; n < GetColumnCount(); n++ ) for ( unsigned n = 0; n < m_header.GetColumnCount(); n++ )
{ {
const wxHeaderColumn& c = GetColumn(n); const wxHeaderColumn& c = m_header.GetColumn(n);
if (c.IsShown() && c.IsResizeable()) if (c.IsShown() && c.IsResizeable())
{ {
hasResizableColumns = true; hasResizableColumns = true;
@@ -403,7 +529,7 @@ void wxHeaderCtrl::DoInsertItem(const wxHeaderColumn& col, unsigned int idx)
.TurnOnOrOff(!hasResizableColumns, HDS_NOSIZING); .TurnOnOrOff(!hasResizableColumns, HDS_NOSIZING);
} }
void wxHeaderCtrl::DoSetColumnsOrder(const wxArrayInt& order) void wxMSWHeaderCtrl::SetColumnsOrder(const wxArrayInt& order)
{ {
wxArrayInt orderShown; wxArrayInt orderShown;
orderShown.reserve(m_numColumns); orderShown.reserve(m_numColumns);
@@ -411,7 +537,7 @@ void wxHeaderCtrl::DoSetColumnsOrder(const wxArrayInt& order)
for ( unsigned n = 0; n < m_numColumns; n++ ) for ( unsigned n = 0; n < m_numColumns; n++ )
{ {
const int idx = order[n]; const int idx = order[n];
if ( GetColumn(idx).IsShown() ) if ( m_header.GetColumn(idx).IsShown() )
orderShown.push_back(MSWToNativeIdx(idx)); orderShown.push_back(MSWToNativeIdx(idx));
} }
@@ -423,7 +549,7 @@ void wxHeaderCtrl::DoSetColumnsOrder(const wxArrayInt& order)
m_colIndices = order; m_colIndices = order;
} }
wxArrayInt wxHeaderCtrl::DoGetColumnsOrder() const wxArrayInt wxMSWHeaderCtrl::GetColumnsOrder() const
{ {
// we don't use Header_GetOrderArray() here because it doesn't return // we don't use Header_GetOrderArray() here because it doesn't return
// information about the hidden columns, instead we just save the columns // information about the hidden columns, instead we just save the columns
@@ -432,10 +558,10 @@ wxArrayInt wxHeaderCtrl::DoGetColumnsOrder() const
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxHeaderCtrl indexes and positions translation // wxMSWHeaderCtrl indexes and positions translation
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
int wxHeaderCtrl::MSWToNativeIdx(int idx) int wxMSWHeaderCtrl::MSWToNativeIdx(int idx)
{ {
// don't check for GetColumn(idx).IsShown() as it could have just became // don't check for GetColumn(idx).IsShown() as it could have just became
// false and we may be called from DoUpdate() to delete the old column // false and we may be called from DoUpdate() to delete the old column
@@ -446,7 +572,7 @@ int wxHeaderCtrl::MSWToNativeIdx(int idx)
int item = idx; int item = idx;
for ( int i = 0; i < idx; i++ ) for ( int i = 0; i < idx; i++ )
{ {
if ( GetColumn(i).IsHidden() ) if ( m_header.GetColumn(i).IsHidden() )
item--; // one less column the native control knows about item--; // one less column the native control knows about
} }
@@ -455,7 +581,7 @@ int wxHeaderCtrl::MSWToNativeIdx(int idx)
return item; return item;
} }
int wxHeaderCtrl::MSWFromNativeIdx(int item) int wxMSWHeaderCtrl::MSWFromNativeIdx(int item)
{ {
wxASSERT_MSG( item >= 0 && item < GetShownColumnsCount(), wxASSERT_MSG( item >= 0 && item < GetShownColumnsCount(),
"column index out of range" ); "column index out of range" );
@@ -468,7 +594,7 @@ int wxHeaderCtrl::MSWFromNativeIdx(int item)
if ( n > idx ) if ( n > idx )
break; break;
if ( GetColumn(n).IsHidden() ) if ( m_header.GetColumn(n).IsHidden() )
idx++; idx++;
} }
@@ -477,7 +603,7 @@ int wxHeaderCtrl::MSWFromNativeIdx(int item)
return idx; return idx;
} }
int wxHeaderCtrl::MSWToNativeOrder(int pos) int wxMSWHeaderCtrl::MSWToNativeOrder(int pos)
{ {
wxASSERT_MSG( pos >= 0 && static_cast<unsigned>(pos) < m_numColumns, wxASSERT_MSG( pos >= 0 && static_cast<unsigned>(pos) < m_numColumns,
"column position out of range" ); "column position out of range" );
@@ -485,7 +611,7 @@ int wxHeaderCtrl::MSWToNativeOrder(int pos)
int order = pos; int order = pos;
for ( int n = 0; n < pos; n++ ) for ( int n = 0; n < pos; n++ )
{ {
if ( GetColumn(m_colIndices[n]).IsHidden() ) if ( m_header.GetColumn(m_colIndices[n]).IsHidden() )
order--; order--;
} }
@@ -494,7 +620,7 @@ int wxHeaderCtrl::MSWToNativeOrder(int pos)
return order; return order;
} }
int wxHeaderCtrl::MSWFromNativeOrder(int order) int wxMSWHeaderCtrl::MSWFromNativeOrder(int order)
{ {
wxASSERT_MSG( order >= 0 && order < GetShownColumnsCount(), wxASSERT_MSG( order >= 0 && order < GetShownColumnsCount(),
"native column position out of range" ); "native column position out of range" );
@@ -505,7 +631,7 @@ int wxHeaderCtrl::MSWFromNativeOrder(int order)
if ( n > pos ) if ( n > pos )
break; break;
if ( GetColumn(m_colIndices[n]).IsHidden() ) if ( m_header.GetColumn(m_colIndices[n]).IsHidden() )
pos++; pos++;
} }
@@ -515,10 +641,10 @@ int wxHeaderCtrl::MSWFromNativeOrder(int order)
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxHeaderCtrl appearance // wxMSWHeaderCtrl appearance
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxMSWHeaderCtrlCustomDraw* wxHeaderCtrl::GetCustomDraw() wxMSWHeaderCtrlCustomDraw* wxMSWHeaderCtrl::GetCustomDraw()
{ {
// There is no need to make the control custom drawn just because it has a // There is no need to make the control custom drawn just because it has a
// custom font, the native control handles the font just fine on its own, // custom font, the native control handles the font just fine on its own,
@@ -542,9 +668,9 @@ wxMSWHeaderCtrlCustomDraw* wxHeaderCtrl::GetCustomDraw()
return m_customDraw; return m_customDraw;
} }
bool wxHeaderCtrl::SetBackgroundColour(const wxColour& colour) bool wxMSWHeaderCtrl::SetBackgroundColour(const wxColour& colour)
{ {
if ( !wxHeaderCtrlBase::SetBackgroundColour(colour) ) if ( !wxControl::SetBackgroundColour(colour) )
return false; return false;
if ( wxMSWHeaderCtrlCustomDraw* customDraw = GetCustomDraw() ) if ( wxMSWHeaderCtrlCustomDraw* customDraw = GetCustomDraw() )
@@ -555,9 +681,9 @@ bool wxHeaderCtrl::SetBackgroundColour(const wxColour& colour)
return true; return true;
} }
bool wxHeaderCtrl::SetForegroundColour(const wxColour& colour) bool wxMSWHeaderCtrl::SetForegroundColour(const wxColour& colour)
{ {
if ( !wxHeaderCtrlBase::SetForegroundColour(colour) ) if ( !wxControl::SetForegroundColour(colour) )
return false; return false;
if ( wxMSWHeaderCtrlCustomDraw* customDraw = GetCustomDraw() ) if ( wxMSWHeaderCtrlCustomDraw* customDraw = GetCustomDraw() )
@@ -568,9 +694,9 @@ bool wxHeaderCtrl::SetForegroundColour(const wxColour& colour)
return true; return true;
} }
bool wxHeaderCtrl::SetFont(const wxFont& font) bool wxMSWHeaderCtrl::SetFont(const wxFont& font)
{ {
if ( !wxHeaderCtrlBase::SetFont(font) ) if ( !wxControl::SetFont(font) )
return false; return false;
if ( wxMSWHeaderCtrlCustomDraw* customDraw = GetCustomDraw() ) if ( wxMSWHeaderCtrlCustomDraw* customDraw = GetCustomDraw() )
@@ -582,10 +708,10 @@ bool wxHeaderCtrl::SetFont(const wxFont& font)
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxHeaderCtrl events // wxMSWHeaderCtrl events
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxEventType wxHeaderCtrl::GetClickEventType(bool dblclk, int button) wxEventType wxMSWHeaderCtrl::GetClickEventType(bool dblclk, int button)
{ {
wxEventType evtType; wxEventType evtType;
switch ( button ) switch ( button )
@@ -613,7 +739,7 @@ wxEventType wxHeaderCtrl::GetClickEventType(bool dblclk, int button)
return evtType; return evtType;
} }
bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) bool wxMSWHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{ {
NMHEADER * const nmhdr = (NMHEADER *)lParam; NMHEADER * const nmhdr = (NMHEADER *)lParam;
@@ -683,7 +809,7 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
case HDN_BEGINTRACKW: case HDN_BEGINTRACKW:
// non-resizable columns can't be resized no matter what, don't // non-resizable columns can't be resized no matter what, don't
// even generate any events for them // even generate any events for them
if ( !GetColumn(idx).IsResizeable() ) if ( !m_header.GetColumn(idx).IsResizeable() )
{ {
veto = true; veto = true;
break; break;
@@ -702,7 +828,7 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
evtType = wxEVT_HEADER_END_RESIZE; evtType = wxEVT_HEADER_END_RESIZE;
// don't generate events with invalid width // don't generate events with invalid width
const int minWidth = GetColumn(idx).GetMinWidth(); const int minWidth = m_header.GetColumn(idx).GetMinWidth();
if ( width < minWidth ) if ( width < minWidth )
width = minWidth; width = minWidth;
@@ -744,7 +870,7 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{ {
// prevent the column from being shrunk beneath its min width // prevent the column from being shrunk beneath its min width
width = nmhdr->pitem->cxy; width = nmhdr->pitem->cxy;
if ( width < GetColumn(idx).GetMinWidth() ) if ( width < m_header.GetColumn(idx).GetMinWidth() )
{ {
// don't generate any events and prevent the change from // don't generate any events and prevent the change from
// happening // happening
@@ -759,7 +885,7 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
evtType = wxEVT_HEADER_RESIZING; evtType = wxEVT_HEADER_RESIZING;
} }
// else // else
// Nnotification arriving after HDN_ENDTRACK is handled normally // Notification arriving after HDN_ENDTRACK is handled normally
// by the control but EVT_HEADER_RESIZING event cannot be generated // by the control but EVT_HEADER_RESIZING event cannot be generated
// because EVT_HEADER_END_RESIZE finalizing the resizing has been // because EVT_HEADER_END_RESIZE finalizing the resizing has been
// already emitted. // already emitted.
@@ -786,7 +912,7 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
} }
// column must have the appropriate flag to be draggable // column must have the appropriate flag to be draggable
if ( !GetColumn(m_colBeingDragged).IsReorderable() ) if ( !m_header.GetColumn(m_colBeingDragged).IsReorderable() )
{ {
veto = true; veto = true;
break; break;
@@ -843,7 +969,7 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
if ( order != -1 ) if ( order != -1 )
event.SetNewOrder(order); event.SetNewOrder(order);
const bool processed = GetEventHandler()->ProcessEvent(event); const bool processed = m_header.GetEventHandler()->ProcessEvent(event);
if ( processed && !event.IsAllowed() ) if ( processed && !event.IsAllowed() )
veto = true; veto = true;
@@ -854,7 +980,7 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
// internal column indices array if this is allowed to go ahead as // internal column indices array if this is allowed to go ahead as
// the native control is going to reorder its columns now // the native control is going to reorder its columns now
if ( evtType == wxEVT_HEADER_END_REORDER ) if ( evtType == wxEVT_HEADER_END_REORDER )
MoveColumnInOrderArray(m_colIndices, idx, order); m_header.MoveColumnInOrderArray(m_colIndices, idx, order);
if ( processed ) if ( processed )
{ {
@@ -874,7 +1000,136 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
return true; return true;
} }
return wxHeaderCtrlBase::MSWOnNotify(idCtrl, lParam, result); return wxControl::MSWOnNotify(idCtrl, lParam, result);
}
// ============================================================================
// wxHeaderCtrl implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxHeaderCtrl construction/destruction
// ----------------------------------------------------------------------------
void wxHeaderCtrl::Init()
{
m_nativeControl = NULL;
}
bool wxHeaderCtrl::Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
long newStyle = style | wxCLIP_CHILDREN | wxTAB_TRAVERSAL;
if ( !wxWindow::Create(parent, id, pos, size, newStyle, name) )
return false;
m_nativeControl = new wxMSWHeaderCtrl(*this);
if ( !m_nativeControl->Create(this,
wxID_ANY,
wxDefaultPosition,
wxDefaultSize,
ApplyHeaderReorderFlagToStyle(wxNO_BORDER),
wxMSWHeaderCtrlNameStr) )
return false;
Bind(wxEVT_SIZE, &wxHeaderCtrl::OnSize, this);
return true;
}
// ----------------------------------------------------------------------------
// wxHeaderCtrl events
// ----------------------------------------------------------------------------
void wxHeaderCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
{
if (m_nativeControl != NULL) // check whether initialisation has been done
{
int cw, ch;
GetClientSize(&cw, &ch);
m_nativeControl->SetSize(0, 0, cw, ch);
}
}
// ----------------------------------------------------------------------------
// wxHeaderCtrl scrolling
// ----------------------------------------------------------------------------
void wxHeaderCtrl::DoScrollHorz(int dx)
{
m_nativeControl->ScrollHorz(dx);
}
// ----------------------------------------------------------------------------
// wxHeaderCtrl geometry calculation
// ----------------------------------------------------------------------------
wxSize wxHeaderCtrl::DoGetBestSize() const
{
return m_nativeControl->GetBestSize();
}
// ----------------------------------------------------------------------------
// wxHeaderCtrl columns managements
// ----------------------------------------------------------------------------
unsigned int wxHeaderCtrl::DoGetCount() const
{
return m_nativeControl->GetCount();
}
void wxHeaderCtrl::DoSetCount(unsigned int count)
{
m_nativeControl->SetCount(count);
}
void wxHeaderCtrl::DoUpdate(unsigned int idx)
{
m_nativeControl->UpdateHeader(idx);
}
void wxHeaderCtrl::DoSetColumnsOrder(const wxArrayInt& order)
{
m_nativeControl->SetColumnsOrder(order);
}
wxArrayInt wxHeaderCtrl::DoGetColumnsOrder() const
{
return m_nativeControl->GetColumnsOrder();
}
// ----------------------------------------------------------------------------
// wxHeaderCtrl composite window
// ----------------------------------------------------------------------------
wxWindowList wxHeaderCtrl::GetCompositeWindowParts() const
{
wxWindowList parts;
parts.push_back(m_nativeControl);
return parts;
}
void wxHeaderCtrl::SetWindowStyleFlag(long style)
{
wxHeaderCtrlBase::SetWindowStyleFlag(style);
// Update the native control style.
long flags = m_nativeControl->GetWindowStyleFlag();
flags = ApplyHeaderReorderFlagToStyle(flags);
m_nativeControl->SetWindowStyleFlag(flags);
}
long wxHeaderCtrl::ApplyHeaderReorderFlagToStyle(long style)
{
if ( HasFlag(wxHD_ALLOW_REORDER) )
return style | wxHD_ALLOW_REORDER;
return style & ~wxHD_ALLOW_REORDER;
} }
#endif // wxHAS_GENERIC_HEADERCTRL #endif // wxHAS_GENERIC_HEADERCTRL

View File

@@ -66,10 +66,14 @@ private:
CPPUNIT_TEST( CellFormatting ); CPPUNIT_TEST( CellFormatting );
WXUISIM_TEST( Editable ); WXUISIM_TEST( Editable );
WXUISIM_TEST( ReadOnly ); WXUISIM_TEST( ReadOnly );
WXUISIM_TEST( ResizeScrolledHeader );
WXUISIM_TEST( ColumnMinWidth );
CPPUNIT_TEST( PseudoTest_NativeHeader ); CPPUNIT_TEST( PseudoTest_NativeHeader );
NONGTK_TEST( LabelClick ); NONGTK_TEST( LabelClick );
NONGTK_TEST( SortClick ); NONGTK_TEST( SortClick );
CPPUNIT_TEST( ColumnOrder ); CPPUNIT_TEST( ColumnOrder );
WXUISIM_TEST( ResizeScrolledHeader );
WXUISIM_TEST( ColumnMinWidth );
CPPUNIT_TEST( PseudoTest_NativeLabels ); CPPUNIT_TEST( PseudoTest_NativeLabels );
NONGTK_TEST( LabelClick ); NONGTK_TEST( LabelClick );
NONGTK_TEST( SortClick ); NONGTK_TEST( SortClick );
@@ -97,6 +101,8 @@ private:
void Editable(); void Editable();
void ReadOnly(); void ReadOnly();
void WindowAsEditorControl(); void WindowAsEditorControl();
void ResizeScrolledHeader();
void ColumnMinWidth();
void PseudoTest_NativeHeader() { ms_nativeheader = true; } void PseudoTest_NativeHeader() { ms_nativeheader = true; }
void PseudoTest_NativeLabels() { ms_nativeheader = false; void PseudoTest_NativeLabels() { ms_nativeheader = false;
ms_nativelabels = true; } ms_nativelabels = true; }
@@ -806,4 +812,81 @@ void GridTestCase::WindowAsEditorControl()
#endif #endif
} }
void GridTestCase::ResizeScrolledHeader()
{
// TODO this test currently works only under Windows unfortunately
#if wxUSE_UIACTIONSIMULATOR && defined(__WXMSW__)
int const startwidth = m_grid->GetColSize(0);
int const draglength = 100;
m_grid->AppendCols(8);
m_grid->Scroll(5, 0);
m_grid->Refresh();
m_grid->Update();
wxRect rect = m_grid->CellToRect(0, 1);
wxPoint point = m_grid->CalcScrolledPosition(rect.GetPosition());
point = m_grid->ClientToScreen(point
+ wxPoint(m_grid->GetRowLabelSize(),
m_grid->GetColLabelSize())
- wxPoint(0, 5));
wxUIActionSimulator sim;
wxYield();
sim.MouseMove(point);
wxYield();
sim.MouseDown();
wxYield();
sim.MouseMove(point + wxPoint(draglength, 0));
wxYield();
sim.MouseUp();
wxYield();
CPPUNIT_ASSERT_EQUAL(startwidth + draglength, m_grid->GetColSize(0));
#endif
}
void GridTestCase::ColumnMinWidth()
{
// TODO this test currently works only under Windows unfortunately
#if wxUSE_UIACTIONSIMULATOR && defined(__WXMSW__)
int const startminwidth = m_grid->GetColMinimalAcceptableWidth();
m_grid->SetColMinimalAcceptableWidth(startminwidth*2);
int const newminwidth = m_grid->GetColMinimalAcceptableWidth();
int const startwidth = m_grid->GetColSize(0);
CPPUNIT_ASSERT(m_grid->GetColMinimalAcceptableWidth() < startwidth);
wxRect rect = m_grid->CellToRect(0, 1);
wxPoint point = m_grid->CalcScrolledPosition(rect.GetPosition());
point = m_grid->ClientToScreen(point
+ wxPoint(m_grid->GetRowLabelSize(),
m_grid->GetColLabelSize())
- wxPoint(0, 5));
wxUIActionSimulator sim;
// Drag to reach the minimal width.
wxYield();
sim.MouseMove(point);
wxYield();
sim.MouseDown();
wxYield();
sim.MouseMove(point - wxPoint(startwidth - startminwidth, 0));
wxYield();
sim.MouseUp();
wxYield();
if ( ms_nativeheader )
CPPUNIT_ASSERT_EQUAL(startwidth, m_grid->GetColSize(0));
else
CPPUNIT_ASSERT_EQUAL(newminwidth, m_grid->GetColSize(0));
#endif
}
#endif //wxUSE_GRID #endif //wxUSE_GRID