- 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:
@@ -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();
|
||||
}
|
||||
|
Reference in New Issue
Block a user