- Rewrite wxHeaderCtrl to be virtual-like: even if we don't need an infinite

number of columns in it, it turns out that getting column information from
  the associated control is much easier than copying it into the control.
- Provide wxHeaderCtrlSimple derived class which can be used easily if
  callback approach of wxHeaderCtrl is not needed.
- Because of wxHeaderCtrl virtualization, port-specific implementations of
  wxHeaderColumn are not needed any more and were removed.
- Use wxHeaderCtrl in the generic wxDataViewCtrl: this means that column
  events are broken right now in it as they haven't been implemented by
  wxHeaderCtrl yet, this will be fixed a.s.a.p.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57161 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-12-07 14:47:55 +00:00
parent bc0289bf5e
commit e2bfe6731e
30 changed files with 725 additions and 2034 deletions

View File

@@ -45,6 +45,7 @@
#include "wx/list.h"
#include "wx/listimpl.cpp"
#include "wx/imaglist.h"
#include "wx/headerctrl.h"
//-----------------------------------------------------------------------------
// classes
@@ -70,195 +71,33 @@ static const int EXPANDER_OFFSET = 1;
// wxDataViewHeaderWindow
//-----------------------------------------------------------------------------
// on wxMSW the header window (only that part however) can be made native!
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
#define USE_NATIVE_HEADER_WINDOW
#include "wx/headerctrl.h"
#endif
//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;
// NB: for some reason, this class must be dllexport'ed or we get warnings from
// MSVC in DLL build
class WXDLLIMPEXP_ADV wxDataViewHeaderWindowBase : public
#ifdef USE_NATIVE_HEADER_WINDOW
wxHeaderCtrl
#else
wxControl
#endif
class wxDataViewHeaderWindow : public wxHeaderCtrl
{
public:
wxDataViewHeaderWindowBase()
{ m_owner = NULL; }
bool Create(wxDataViewCtrl *parent, wxWindowID id,
const wxPoint &pos, const wxSize &size,
const wxString &name)
wxDataViewHeaderWindow(wxDataViewCtrl *parent)
: wxHeaderCtrl(parent)
{
return wxWindow::Create(parent, id, pos, size, wxNO_BORDER, name);
}
void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
wxDataViewCtrl *GetOwner() { return m_owner; }
// called on column addition/removal
virtual void UpdateDisplay() { /* by default, do nothing */ }
// returns the n-th column
virtual wxDataViewColumn *GetColumn(unsigned int n)
{
wxASSERT(m_owner);
wxDataViewColumn *ret = m_owner->GetColumn(n);
wxASSERT(ret);
return ret;
}
wxDataViewCtrl *GetOwner() const
{ return static_cast<wxDataViewCtrl *>(GetParent()); }
protected:
wxDataViewCtrl *m_owner;
// sends an event generated from the n-th wxDataViewColumn
void SendEvent(wxEventType type, unsigned int n);
};
#ifdef USE_NATIVE_HEADER_WINDOW
#define COLUMN_WIDTH_OFFSET 2
#define wxDataViewHeaderWindowMSW wxDataViewHeaderWindow
class wxDataViewHeaderWindowMSW : public wxDataViewHeaderWindowBase
{
public:
wxDataViewHeaderWindowMSW(wxDataViewCtrl *parent)
virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
{
Create(parent);
return *(GetOwner()->GetColumn(idx));
}
bool Create(wxDataViewCtrl *parent);
// called when any column setting is changed and/or changed
// the column count
virtual void UpdateDisplay();
virtual void OnInternalIdle();
// called Refresh afterwards
virtual void ScrollWindow(int dx, int dy, const wxRect *rect = NULL);
virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
protected:
virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags);
wxSize DoGetBestSize() const;
unsigned int GetColumnIdxFromHeader(NMHEADER *nmHDR);
wxDataViewColumn *GetColumnFromHeader(NMHEADER *nmHDR)
{ return GetColumn(GetColumnIdxFromHeader(nmHDR)); }
int m_scrollOffsetX;
int m_buttonHeight;
bool m_vetoColumnDrag;
bool m_delayedUpdate;
private:
DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW)
DECLARE_NO_COPY_CLASS(wxDataViewHeaderWindow)
};
#else // !defined(__WXMSW__)
#define HEADER_WINDOW_HEIGHT 25
#define HEADER_HORIZ_BORDER 5
#define HEADER_VERT_BORDER 3
#define wxGenericDataViewHeaderWindow wxDataViewHeaderWindow
class wxGenericDataViewHeaderWindow : public wxDataViewHeaderWindowBase
{
public:
wxGenericDataViewHeaderWindow( wxDataViewCtrl *parent,
wxWindowID id = wxID_ANY,
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
const wxString &name = wxT("wxdataviewctrlheaderwindow") )
{
Init();
Create(parent, id, pos, size, name);
}
bool Create(wxDataViewCtrl *parent, wxWindowID id,
const wxPoint &pos, const wxSize &size,
const wxString &name);
~wxGenericDataViewHeaderWindow()
{
delete m_resizeCursor;
}
virtual void UpdateDisplay() { Refresh(); }
// event handlers:
void OnPaint( wxPaintEvent &event );
void OnMouse( wxMouseEvent &event );
void OnSetFocus( wxFocusEvent &event );
protected:
// vars used for column resizing:
wxCursor *m_resizeCursor;
const wxCursor *m_currentCursor;
bool m_isDragging;
bool m_dirty; // needs refresh?
int m_hover; // index of the column under the mouse
int m_column; // index of the column being resized
int m_currentX; // divider line position in logical (unscrolled) coords
int m_minX; // minimal position beyond which the divider line
// can't be dragged in logical coords
// the pen used to draw the current column width drag line
// when resizing the columsn
wxPen m_penCurrent;
// internal utilities:
void Init()
{
m_currentCursor = (wxCursor *) NULL;
m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
m_isDragging = false;
m_dirty = false;
m_hover = wxNOT_FOUND;
m_column = wxNOT_FOUND;
m_currentX = 0;
m_minX = 0;
wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
m_penCurrent = wxPen(col, 1, wxSOLID);
}
void AdjustDC(wxDC& dc);
private:
DECLARE_DYNAMIC_CLASS(wxGenericDataViewHeaderWindow)
DECLARE_EVENT_TABLE()
};
#endif // defined(__WXMSW__)
//-----------------------------------------------------------------------------
// wxDataViewRenameTimer
//-----------------------------------------------------------------------------
@@ -1170,682 +1009,6 @@ wxDataViewIconTextRenderer::GetValueFromEditorCtrl(wxControl* WXUNUSED(editor),
return false;
}
// ---------------------------------------------------------
// wxDataViewColumn
// ---------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
unsigned int model_column,
int width, wxAlignment align, int flags ) :
wxDataViewColumnBase( title, cell, model_column, width, align, flags )
{
wxDataViewColumnBase::SetWidth(width == wxCOL_WIDTH_DEFAULT
? wxDVC_DEFAULT_WIDTH
: width);
SetTitle(title);
SetAlignment(align);
SetFlags(flags);
}
wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
unsigned int model_column,
int width, wxAlignment align, int flags ) :
wxDataViewColumnBase( bitmap, cell, model_column, width, align, flags )
{
wxDataViewColumnBase::SetWidth(width == wxCOL_WIDTH_DEFAULT
? wxDVC_DEFAULT_WIDTH
: width);
SetBitmap(bitmap);
SetAlignment(align);
SetFlags(flags);
}
void wxDataViewColumn::SetFlags(int flags)
{
if ( flags != GetFlags() )
{
wxDataViewColumnBase::SetFlags(flags);
// tell our owner to e.g. update its scrollbars:
if ( GetOwner() )
GetOwner()->OnColumnChange();
}
}
void wxDataViewColumn::SetSortOrder( bool ascending )
{
if ( ascending == IsSortOrderAscending() )
return;
wxDataViewColumnBase::SetSortOrder(ascending);
// Update header button
if (GetOwner())
GetOwner()->OnColumnChange();
}
void wxDataViewColumn::SetInternalWidth( int width )
{
if ( width == GetWidth() )
return;
wxDataViewColumnBase::SetWidth(width);
// the scrollbars of the wxDataViewCtrl needs to be recalculated!
if (m_owner && m_owner->m_clientArea)
m_owner->m_clientArea->RecalculateDisplay();
}
void wxDataViewColumn::SetWidth( int width )
{
if ( width == wxCOL_WIDTH_DEFAULT )
width = wxDVC_DEFAULT_WIDTH;
if ( width == GetWidth() )
return;
if (m_owner->m_headerArea)
m_owner->m_headerArea->UpdateDisplay();
SetInternalWidth(width);
}
int wxDataViewColumn::GetWidth() const
{
int width = wxDataViewColumnBase::GetWidth();
return width == wxCOL_WIDTH_DEFAULT ? wxDVC_DEFAULT_WIDTH : width;
}
//-----------------------------------------------------------------------------
// wxDataViewHeaderWindowBase
//-----------------------------------------------------------------------------
void wxDataViewHeaderWindowBase::SendEvent(wxEventType type, unsigned int n)
{
wxWindow *parent = GetParent();
wxDataViewEvent le(type, parent->GetId());
le.SetEventObject(parent);
le.SetColumn(n);
le.SetDataViewColumn(GetColumn(n));
le.SetModel(GetOwner()->GetModel());
// for events created by wxDataViewHeaderWindow the
// row / value fields are not valid
parent->GetEventHandler()->ProcessEvent(le);
}
#ifdef USE_NATIVE_HEADER_WINDOW
// implemented in msw/listctrl.cpp:
int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick);
IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindowMSW, wxWindow)
bool wxDataViewHeaderWindowMSW::Create(wxDataViewCtrl *parent)
{
m_owner = parent;
m_scrollOffsetX = 0;
m_delayedUpdate = false;
m_vetoColumnDrag = false;
m_buttonHeight = wxRendererNative::Get().GetHeaderButtonHeight( this );
return wxHeaderCtrl::Create(parent, wxID_ANY);
}
wxSize wxDataViewHeaderWindowMSW::DoGetBestSize() const
{
return wxSize( 80, m_buttonHeight+2 );
}
void wxDataViewHeaderWindowMSW::OnInternalIdle()
{
if (m_delayedUpdate)
{
m_delayedUpdate = false;
UpdateDisplay();
}
}
void wxDataViewHeaderWindowMSW::UpdateDisplay()
{
// remove old columns
DeleteAllColumns();
// add the updated array of columns to the header control
const unsigned int cols = GetOwner()->GetColumnCount();
for (unsigned int i = 0; i < cols; i++)
{
wxDataViewColumn * const col = GetColumn( i );
if (col->IsHidden())
continue; // don't add it!
// we store the column index to use later as client data (we need to do
// it since column indices in the control and the model may not be the
// same if any columns have been hidden)
col->SetClientData(i);
AppendColumn(*col);
if ( col->IsSortable() && GetOwner()->GetSortingColumn() == col )
{
ShowSortIndicator(GetColumnCount() - 1, col->IsSortOrderAscending());
}
#if 0
// the native wxMSW implementation of the header window
// draws the column separator COLUMN_WIDTH_OFFSET pixels
// on the right: to correct this effect we make the column
// exactly COLUMN_WIDTH_OFFSET wider (for the first column):
if (i == 0)
hdi.cxy += COLUMN_WIDTH_OFFSET;
#endif
}
}
unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER *nmHDR)
{
unsigned int idx;
// NOTE: we don't just return nmHDR->iItem because when there are
// hidden columns, nmHDR->iItem may be different from
// nmHDR->pitem->lParam
if (nmHDR->pitem && nmHDR->pitem->mask & HDI_LPARAM)
{
idx = (unsigned int)nmHDR->pitem->lParam;
return idx;
}
HDITEM item;
item.mask = HDI_LPARAM;
Header_GetItem((HWND)m_hWnd, nmHDR->iItem, &item);
return (unsigned int)item.lParam;
}
bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{
NMHDR *nmhdr = (NMHDR *)lParam;
// is it a message from the header?
if ( nmhdr->hwndFrom != (HWND)m_hWnd )
return wxWindow::MSWOnNotify(idCtrl, lParam, result);
NMHEADER *nmHDR = (NMHEADER *)nmhdr;
switch ( nmhdr->code )
{
case NM_RELEASEDCAPTURE:
{
// user has released the mouse
m_vetoColumnDrag = false;
}
break;
case HDN_BEGINTRACK:
// user has started to resize a column:
// do we need to veto it?
if (!GetColumn(nmHDR->iItem)->IsResizeable())
{
// veto it!
*result = TRUE;
}
break;
case HDN_BEGINDRAG:
// valid column
if (nmHDR->iItem != -1)
{
// user has started to reorder a valid column
if ((m_vetoColumnDrag == true) || (!GetColumn(nmHDR->iItem)->IsReorderable()))
{
// veto it!
*result = TRUE;
m_vetoColumnDrag = true;
}
}
else
{
// veto it!
m_vetoColumnDrag = true;
}
break;
case HDN_ENDDRAG: // user has finished reordering a column
{
wxDataViewColumn *col = GetColumn(nmHDR->iItem);
unsigned int new_pos = nmHDR->pitem->iOrder;
m_owner->ColumnMoved( col, new_pos );
m_delayedUpdate = true;
}
break;
case HDN_ITEMCHANGING:
if (nmHDR->pitem != NULL &&
(nmHDR->pitem->mask & HDI_WIDTH) != 0)
{
int minWidth = GetColumnFromHeader(nmHDR)->GetMinWidth();
if (nmHDR->pitem->cxy < minWidth)
{
// do not allow the user to resize this column under
// its minimal width:
*result = TRUE;
}
}
break;
case HDN_ITEMCHANGED: // user is resizing a column
case HDN_ENDTRACK: // user has finished resizing a column
// update the width of the modified column:
if (nmHDR->pitem != NULL &&
(nmHDR->pitem->mask & HDI_WIDTH) != 0)
{
unsigned int idx = GetColumnIdxFromHeader(nmHDR);
unsigned int w = nmHDR->pitem->cxy;
wxDataViewColumn *col = GetColumn(idx);
// see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET
if (idx == 0 && w > COLUMN_WIDTH_OFFSET)
w -= COLUMN_WIDTH_OFFSET;
if (w >= (unsigned)col->GetMinWidth())
col->SetInternalWidth(w);
}
break;
case HDN_ITEMCLICK:
{
unsigned int idx = GetColumnIdxFromHeader(nmHDR);
wxDataViewModel * model = GetOwner()->GetModel();
if(nmHDR->iButton == 0)
{
wxDataViewColumn *col = GetColumn(idx);
if(col->IsSortable())
{
if(model && m_owner->GetSortingColumn() == col)
{
bool order = col->IsSortOrderAscending();
col->SetSortOrder(!order);
}
else if(model)
{
m_owner->SetSortingColumn(col);
}
}
UpdateDisplay();
if(model)
model->Resort();
}
wxEventType evt = nmHDR->iButton == 0 ?
wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
SendEvent(evt, idx);
}
break;
case NM_RCLICK:
{
// NOTE: for some reason (i.e. for a bug in Windows)
// the HDN_ITEMCLICK notification is not sent on
// right clicks, so we need to handle NM_RCLICK
POINT ptClick;
int column = wxMSWGetColumnClicked(nmhdr, &ptClick);
if (column != wxNOT_FOUND)
{
HDITEM item;
item.mask = HDI_LPARAM;
Header_GetItem((HWND)m_hWnd, column, &item);
// 'idx' may be different from 'column' if there are
// hidden columns...
unsigned int idx = (unsigned int)item.lParam;
SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
idx);
}
}
break;
case HDN_GETDISPINFOW:
// see wxListCtrl::MSWOnNotify for more info!
break;
case HDN_ITEMDBLCLICK:
{
unsigned int idx = GetColumnIdxFromHeader(nmHDR);
int w = GetOwner()->GetBestColumnWidth(idx);
// update the native control:
HDITEM hd;
ZeroMemory(&hd, sizeof(hd));
hd.mask = HDI_WIDTH;
hd.cxy = w;
Header_SetItem(GetHwnd(),
nmHDR->iItem, // NOTE: we don't want 'idx' here!
&hd);
// update the wxDataViewColumn class:
GetColumn(idx)->SetInternalWidth(w);
}
break;
default:
return wxWindow::MSWOnNotify(idCtrl, lParam, result);
}
return true;
}
void wxDataViewHeaderWindowMSW::ScrollWindow(int dx, int WXUNUSED(dy),
const wxRect * WXUNUSED(rect))
{
m_scrollOffsetX += dx;
GetParent()->Layout();
}
void wxDataViewHeaderWindowMSW::DoSetSize(int x, int y,
int w, int h,
int f)
{
// TODO: why is there a border + 2px around it?
wxControl::DoSetSize( x+m_scrollOffsetX+1, y+1, w-m_scrollOffsetX-2, h-2, f );
}
#else // !defined(__WXMSW__)
IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow, wxWindow)
BEGIN_EVENT_TABLE(wxGenericDataViewHeaderWindow, wxWindow)
EVT_PAINT (wxGenericDataViewHeaderWindow::OnPaint)
EVT_MOUSE_EVENTS (wxGenericDataViewHeaderWindow::OnMouse)
EVT_SET_FOCUS (wxGenericDataViewHeaderWindow::OnSetFocus)
END_EVENT_TABLE()
bool wxGenericDataViewHeaderWindow::Create(wxDataViewCtrl *parent, wxWindowID id,
const wxPoint &pos, const wxSize &size,
const wxString &name )
{
m_owner = parent;
if (!wxDataViewHeaderWindowBase::Create(parent, id, pos, size, name))
return false;
wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
SetBackgroundStyle( wxBG_STYLE_CUSTOM );
SetOwnForegroundColour( attr.colFg );
SetOwnBackgroundColour( attr.colBg );
if (!m_hasFont)
SetOwnFont( attr.font );
// set our size hints: wxDataViewCtrl will put this wxWindow inside
// a wxBoxSizer and in order to avoid super-big header windows,
// we need to set our height as fixed
SetMinSize(wxSize(-1, HEADER_WINDOW_HEIGHT));
SetMaxSize(wxSize(-1, HEADER_WINDOW_HEIGHT));
return true;
}
void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
{
int w, h;
GetClientSize( &w, &h );
wxAutoBufferedPaintDC dc( this );
dc.SetBackground(GetBackgroundColour());
dc.Clear();
int xpix;
m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
int x;
m_owner->GetViewStart( &x, NULL );
// account for the horz scrollbar offset
dc.SetDeviceOrigin( -x * xpix, 0 );
dc.SetFont( GetFont() );
unsigned int cols = GetOwner()->GetColumnCount();
unsigned int i;
int xpos = 0;
for (i = 0; i < cols; i++)
{
wxDataViewColumn *col = GetColumn( i );
if (col->IsHidden())
continue; // skip it!
int cw = col->GetWidth();
int ch = h;
wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE;
if (col->IsSortable() && GetOwner()->GetSortingColumn() == col)
{
if (col->IsSortOrderAscending())
sortArrow = wxHDR_SORT_ICON_UP;
else
sortArrow = wxHDR_SORT_ICON_DOWN;
}
int state = 0;
if (m_parent->IsEnabled())
{
if ((int) i == m_hover)
state = wxCONTROL_CURRENT;
}
else
{
state = (int) wxCONTROL_DISABLED;
}
wxRendererNative::Get().DrawHeaderButton
(
this,
dc,
wxRect(xpos, 0, cw, ch-1),
state,
sortArrow
);
// align as required the column title:
int x = xpos;
wxSize titleSz = dc.GetTextExtent(col->GetTitle());
switch (col->GetAlignment())
{
case wxALIGN_LEFT:
x += HEADER_HORIZ_BORDER;
break;
case wxALIGN_RIGHT:
x += cw - titleSz.GetWidth() - HEADER_HORIZ_BORDER;
break;
default:
case wxALIGN_CENTER:
case wxALIGN_CENTER_HORIZONTAL:
x += (cw - titleSz.GetWidth() - 2 * HEADER_HORIZ_BORDER)/2;
break;
}
// always center the title vertically:
int y = wxMax((ch - titleSz.GetHeight()) / 2, HEADER_VERT_BORDER);
dc.SetClippingRegion( xpos+HEADER_HORIZ_BORDER,
HEADER_VERT_BORDER,
wxMax(cw - 2 * HEADER_HORIZ_BORDER, 1), // width
wxMax(ch - 2 * HEADER_VERT_BORDER, 1)); // height
dc.DrawText( col->GetTitle(), x, y );
dc.DestroyClippingRegion();
xpos += cw;
}
}
void wxGenericDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
{
GetParent()->SetFocus();
event.Skip();
}
void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent &event )
{
// we want to work with logical coords
int x;
m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
int y = event.GetY();
if (m_isDragging)
{
// we don't draw the line beyond our window,
// but we allow dragging it there
int w = 0;
GetClientSize( &w, NULL );
m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
w -= 6;
if (event.ButtonUp())
{
m_isDragging = false;
if (HasCapture())
ReleaseMouse();
m_dirty = true;
}
m_currentX = wxMax(m_minX + 7, x);
if (m_currentX < w)
{
GetColumn(m_column)->SetWidth(m_currentX - m_minX);
Refresh();
GetOwner()->Refresh();
}
}
else // not dragging
{
m_minX = 0;
m_column = wxNOT_FOUND;
bool hit_border = false;
// end of the current column
int xpos = 0;
// find the column where this event occured
int countCol = m_owner->GetColumnCount();
for (int column = 0; column < countCol; column++)
{
wxDataViewColumn *p = GetColumn(column);
if (p->IsHidden())
continue; // skip if not shown
xpos += p->GetWidth();
m_column = column;
if ((abs(x-xpos) < 3) && (y < 22))
{
hit_border = true;
break;
}
if (x < xpos)
{
// inside the column
break;
}
m_minX = xpos;
}
int old_hover = m_hover;
m_hover = m_column;
if (event.Leaving())
m_hover = wxNOT_FOUND;
if (old_hover != m_hover)
Refresh();
if (m_column == wxNOT_FOUND)
return;
bool resizeable = GetColumn(m_column)->IsResizeable();
if (event.LeftDClick() && resizeable)
{
GetColumn(m_column)->SetWidth(GetOwner()->GetBestColumnWidth(m_column));
Refresh();
}
else if (event.LeftDown() || event.RightUp())
{
if (hit_border && event.LeftDown() && resizeable)
{
m_isDragging = true;
CaptureMouse();
m_currentX = x;
}
else // click on a column
{
wxDataViewModel * model = GetOwner()->GetModel();
wxEventType evt = event.LeftDown() ?
wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
SendEvent(evt, m_column);
//Left click the header
if(event.LeftDown())
{
wxDataViewColumn *col = GetColumn(m_column);
if(col->IsSortable())
{
wxDataViewColumn* sortCol = m_owner->GetSortingColumn();
if(model && sortCol == col)
{
bool order = col->IsSortOrderAscending();
col->SetSortOrder(!order);
}
else if(model)
{
m_owner->SetSortingColumn(col);
}
}
UpdateDisplay();
if(model)
model->Resort();
//Send the column sorted event
SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, m_column);
}
}
}
else if (event.Moving())
{
if (hit_border && resizeable)
m_currentCursor = m_resizeCursor;
else
m_currentCursor = wxSTANDARD_CURSOR;
SetCursor(*m_currentCursor);
}
}
}
void wxGenericDataViewHeaderWindow::AdjustDC(wxDC& dc)
{
int xpix, x;
m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
m_owner->GetViewStart( &x, NULL );
// shift the DC origin to match the position of the main window horizontal
// scrollbar: this allows us to always use logical coords
dc.SetDeviceOrigin( -x * xpix, 0 );
}
#endif // defined(__WXMSW__)
//-----------------------------------------------------------------------------
// wxDataViewRenameTimer
//-----------------------------------------------------------------------------
@@ -4105,7 +3268,7 @@ bool wxDataViewCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *col )
void wxDataViewCtrl::OnColumnChange()
{
if (m_headerArea)
m_headerArea->UpdateDisplay();
m_headerArea->SetColumnCount(GetColumnCount());
m_clientArea->UpdateDisplay();
}