Implement scrolling for MSW wxHeaderCtrl correctly

Due to lack of support for horizontal scrolling in the native control,
scrolling it was implementing by offsetting the entire control window.
However this didn't work correctly when the window was not positioned
at the leftmost border of its parent window, as the part of it that was
scrolled off could still be visible in this case, and this is exactly
what happened when the native header was used in wxGrid: scrolling it
overwrote the corner part of wxGrid.

Fix this by embedding the actual native control inside an outer wxWindow,
to ensure that the scrolled off part is clipped by the parent window.

Note that this commit is best viewed with "git show --color-moved" as
most of the code was just moved from the header into the implementation
file and is not really new.
This commit is contained in:
Ilya Sinitsyn
2019-09-04 02:05:19 +07:00
committed by Vadim Zeitlin
parent e5d59c6b7f
commit 120b33746a
2 changed files with 338 additions and 149 deletions

View File

@@ -10,15 +10,15 @@
#ifndef _WX_MSW_HEADERCTRL_H_
#define _WX_MSW_HEADERCTRL_H_
class WXDLLIMPEXP_FWD_CORE wxImageList;
#include "wx/compositewin.h"
class wxMSWHeaderCtrlCustomDraw;
class wxMSWHeaderCtrl;
// ----------------------------------------------------------------------------
// wxHeaderCtrl
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_CORE wxHeaderCtrl : public wxHeaderCtrlBase
class WXDLLIMPEXP_CORE wxHeaderCtrl : public wxCompositeWindow<wxHeaderCtrlBase>
{
public:
wxHeaderCtrl()
@@ -45,22 +45,15 @@ public:
long style = wxHD_DEFAULT_STYLE,
const wxString& name = wxHeaderCtrlNameStr);
virtual ~wxHeaderCtrl();
// 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;
// Window style handling.
virtual void SetWindowStyleFlag(long style) wxOVERRIDE;
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 void DoSetSize(int x, int y,
int width, int height,
int sizeFlags = wxSIZE_AUTO) wxOVERRIDE;
private:
// implement base class pure virtuals
// Implement base class pure virtuals.
virtual void DoSetCount(unsigned int count) wxOVERRIDE;
virtual unsigned int DoGetCount() const wxOVERRIDE;
virtual void DoUpdate(unsigned int idx) wxOVERRIDE;
@@ -70,81 +63,22 @@ private:
virtual void DoSetColumnsOrder(const wxArrayInt& order) wxOVERRIDE;
virtual wxArrayInt DoGetColumnsOrder() const wxOVERRIDE;
// 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;
// Pure virtual method inherited from wxCompositeWindow.
virtual wxWindowList GetCompositeWindowParts() const wxOVERRIDE;
// common part of all ctors
// 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);
// Events.
void OnSize(wxSizeEvent& event);
// 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();
// Style flag helper function.
long ApplyHeaderReorderFlagToStyle(long style);
// 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;
// The native header control.
wxMSWHeaderCtrl* m_nativeControl;
friend class wxMSWHeaderCtrl;
wxDECLARE_NO_COPY_CLASS(wxHeaderCtrl);
};