1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/datavgen.cpp
3 // Purpose: wxDataViewCtrl generic implementation
4 // Author: Robert Roebling
5 // Modified by: Francesco Montorsi, Guru Kathiresan, Otto Wyss
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_DATAVIEWCTRL
20 #include "wx/dataview.h"
22 #ifdef wxUSE_GENERICDATAVIEWCTRL
26 #include "wx/msw/private.h"
27 #include "wx/msw/wrapwin.h"
28 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
32 #include "wx/dcclient.h"
34 #include "wx/settings.h"
35 #include "wx/msgdlg.h"
36 #include "wx/dcscreen.h"
39 #include "wx/stockitem.h"
40 #include "wx/calctrl.h"
41 #include "wx/popupwin.h"
42 #include "wx/renderer.h"
43 #include "wx/dcbuffer.h"
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
52 static const int SCROLL_UNIT_X
= 15;
54 // the cell padding on the left/right
55 static const int PADDING_RIGHTLEFT
= 3;
57 // the cell padding on the top/bottom
58 static const int PADDING_TOPBOTTOM
= 1;
61 //-----------------------------------------------------------------------------
62 // wxDataViewHeaderWindow
63 //-----------------------------------------------------------------------------
65 #define USE_NATIVE_HEADER_WINDOW 1
67 // NB: for some reason, this class must be dllexport'ed or we get warnings from
69 class WXDLLIMPEXP_ADV wxDataViewHeaderWindowBase
: public wxControl
72 wxDataViewHeaderWindowBase()
75 bool Create(wxDataViewCtrl
*parent
, wxWindowID id
,
76 const wxPoint
&pos
, const wxSize
&size
,
79 return wxWindow::Create(parent
, id
, pos
, size
, wxNO_BORDER
, name
);
82 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
83 wxDataViewCtrl
*GetOwner() { return m_owner
; }
85 // called on column addition/removal
86 virtual void UpdateDisplay() { /* by default, do nothing */ }
88 // returns the n-th column
89 virtual wxDataViewColumn
*GetColumn(unsigned int n
)
92 wxDataViewColumn
*ret
= m_owner
->GetColumn(n
);
99 wxDataViewCtrl
*m_owner
;
101 // sends an event generated from the n-th wxDataViewColumn
102 void SendEvent(wxEventType type
, unsigned int n
);
105 // on wxMSW the header window (only that part however) can be made native!
106 #if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW
108 #define COLUMN_WIDTH_OFFSET 2
109 #define wxDataViewHeaderWindowMSW wxDataViewHeaderWindow
111 class wxDataViewHeaderWindowMSW
: public wxDataViewHeaderWindowBase
115 wxDataViewHeaderWindowMSW( wxDataViewCtrl
*parent
,
117 const wxPoint
&pos
= wxDefaultPosition
,
118 const wxSize
&size
= wxDefaultSize
,
119 const wxString
&name
= wxT("wxdataviewctrlheaderwindow") )
121 Create(parent
, id
, pos
, size
, name
);
124 bool Create(wxDataViewCtrl
*parent
, wxWindowID id
,
125 const wxPoint
&pos
, const wxSize
&size
,
126 const wxString
&name
);
128 ~wxDataViewHeaderWindowMSW();
130 // called when any column setting is changed and/or changed
132 virtual void UpdateDisplay();
134 // called when the main window gets scrolled
135 virtual void ScrollWindow(int dx
, int dy
, const wxRect
*rect
= NULL
);
138 virtual bool MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
);
139 virtual void DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
);
141 unsigned int GetColumnIdxFromHeader(NMHEADER
*nmHDR
);
143 wxDataViewColumn
*GetColumnFromHeader(NMHEADER
*nmHDR
)
144 { return GetColumn(GetColumnIdxFromHeader(nmHDR
)); }
147 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW
)
150 #else // !defined(__WXMSW__)
152 #define HEADER_WINDOW_HEIGHT 25
153 #define HEADER_HORIZ_BORDER 5
154 #define HEADER_VERT_BORDER 3
155 #define wxGenericDataViewHeaderWindow wxDataViewHeaderWindow
157 class wxGenericDataViewHeaderWindow
: public wxDataViewHeaderWindowBase
160 wxGenericDataViewHeaderWindow( wxDataViewCtrl
*parent
,
162 const wxPoint
&pos
= wxDefaultPosition
,
163 const wxSize
&size
= wxDefaultSize
,
164 const wxString
&name
= wxT("wxdataviewctrlheaderwindow") )
167 Create(parent
, id
, pos
, size
, name
);
170 bool Create(wxDataViewCtrl
*parent
, wxWindowID id
,
171 const wxPoint
&pos
, const wxSize
&size
,
172 const wxString
&name
);
174 ~wxGenericDataViewHeaderWindow()
176 delete m_resizeCursor
;
181 void OnPaint( wxPaintEvent
&event
);
182 void OnMouse( wxMouseEvent
&event
);
183 void OnSetFocus( wxFocusEvent
&event
);
188 // vars used for column resizing:
190 wxCursor
*m_resizeCursor
;
191 const wxCursor
*m_currentCursor
;
194 bool m_dirty
; // needs refresh?
195 int m_column
; // index of the column being resized
196 int m_currentX
; // divider line position in logical (unscrolled) coords
197 int m_minX
; // minimal position beyond which the divider line
198 // can't be dragged in logical coords
200 // the pen used to draw the current column width drag line
201 // when resizing the columsn
205 // internal utilities:
209 m_currentCursor
= (wxCursor
*) NULL
;
210 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
212 m_isDragging
= false;
215 m_column
= wxNOT_FOUND
;
219 wxColour col
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
);
220 m_penCurrent
= wxPen(col
, 1, wxSOLID
);
224 void AdjustDC(wxDC
& dc
);
227 DECLARE_DYNAMIC_CLASS(wxGenericDataViewHeaderWindow
)
228 DECLARE_EVENT_TABLE()
231 #endif // defined(__WXMSW__)
233 //-----------------------------------------------------------------------------
234 // wxDataViewRenameTimer
235 //-----------------------------------------------------------------------------
237 class wxDataViewRenameTimer
: public wxTimer
240 wxDataViewMainWindow
*m_owner
;
243 wxDataViewRenameTimer( wxDataViewMainWindow
*owner
);
247 //-----------------------------------------------------------------------------
248 // wxDataViewMainWindow
249 //-----------------------------------------------------------------------------
251 WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection
,
254 class wxDataViewMainWindow
: public wxWindow
257 wxDataViewMainWindow( wxDataViewCtrl
*parent
,
259 const wxPoint
&pos
= wxDefaultPosition
,
260 const wxSize
&size
= wxDefaultSize
,
261 const wxString
&name
= wxT("wxdataviewctrlmainwindow") );
262 virtual ~wxDataViewMainWindow();
264 // notifications from wxDataViewListModel
267 bool RowInserted( unsigned int before
);
268 bool RowDeleted( unsigned int row
);
269 bool RowChanged( unsigned int row
);
270 bool ValueChanged( unsigned int col
, unsigned int row
);
271 bool RowsReordered( unsigned int *new_order
);
274 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
275 wxDataViewCtrl
*GetOwner() { return m_owner
; }
276 const wxDataViewCtrl
*GetOwner() const { return m_owner
; }
278 void OnPaint( wxPaintEvent
&event
);
279 void OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
);
280 void OnChar( wxKeyEvent
&event
);
281 void OnMouse( wxMouseEvent
&event
);
282 void OnSetFocus( wxFocusEvent
&event
);
283 void OnKillFocus( wxFocusEvent
&event
);
285 void UpdateDisplay();
286 void RecalculateDisplay();
287 void OnInternalIdle();
289 void OnRenameTimer();
291 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
= NULL
);
293 bool HasCurrentRow() { return m_currentRow
!= (unsigned int)-1; }
294 void ChangeCurrentRow( unsigned int row
);
296 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE
); }
297 bool IsEmpty() { return GetRowCount() == 0; }
299 int GetCountPerPage() const;
300 int GetEndOfLastCol() const;
301 unsigned int GetFirstVisibleRow() const;
302 unsigned int GetLastVisibleRow() const;
303 unsigned int GetRowCount() const;
305 void Select( const wxArrayInt
& aSelections
);
306 void SelectAllRows( bool on
);
307 void SelectRow( unsigned int row
, bool on
);
308 void SelectRows( unsigned int from
, unsigned int to
, bool on
);
309 void ReverseRowSelection( unsigned int row
);
310 bool IsRowSelected( unsigned int row
);
312 void RefreshRow( unsigned int row
);
313 void RefreshRows( unsigned int from
, unsigned int to
);
314 void RefreshRowsAfter( unsigned int firstRow
);
316 // returns the colour to be used for drawing the rules
317 wxColour
GetRuleColour() const
319 return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
);
322 //void EnsureVisible( unsigned int row );
323 wxRect
GetLineRect( unsigned int row
) const;
326 wxDataViewCtrl
*m_owner
;
330 wxDataViewColumn
*m_currentCol
;
331 unsigned int m_currentRow
;
332 wxDataViewSelection m_selection
;
334 wxDataViewRenameTimer
*m_renameTimer
;
342 // for double click logic
343 unsigned int m_lineLastClicked
,
344 m_lineBeforeLastClicked
,
345 m_lineSelectSingleOnUp
;
347 // the pen used to draw horiz/vertical rules
351 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
)
352 DECLARE_EVENT_TABLE()
355 // ---------------------------------------------------------
356 // wxGenericDataViewListModelNotifier
357 // ---------------------------------------------------------
359 class wxGenericDataViewListModelNotifier
: public wxDataViewListModelNotifier
362 wxGenericDataViewListModelNotifier( wxDataViewMainWindow
*mainWindow
)
363 { m_mainWindow
= mainWindow
; }
365 virtual bool RowAppended()
366 { return m_mainWindow
->RowAppended(); }
367 virtual bool RowPrepended()
368 { return m_mainWindow
->RowPrepended(); }
369 virtual bool RowInserted( unsigned int before
)
370 { return m_mainWindow
->RowInserted( before
); }
371 virtual bool RowDeleted( unsigned int row
)
372 { return m_mainWindow
->RowDeleted( row
); }
373 virtual bool RowChanged( unsigned int row
)
374 { return m_mainWindow
->RowChanged( row
); }
375 virtual bool ValueChanged( unsigned int col
, unsigned int row
)
376 { return m_mainWindow
->ValueChanged( col
, row
); }
377 virtual bool RowsReordered( unsigned int *new_order
)
378 { return m_mainWindow
->RowsReordered( new_order
); }
379 virtual bool Cleared()
380 { return m_mainWindow
->Cleared(); }
382 wxDataViewMainWindow
*m_mainWindow
;
385 // ---------------------------------------------------------
386 // wxDataViewRenderer
387 // ---------------------------------------------------------
389 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer
, wxDataViewRendererBase
)
391 wxDataViewRenderer::wxDataViewRenderer( const wxString
&varianttype
,
392 wxDataViewCellMode mode
,
394 wxDataViewRendererBase( varianttype
, mode
, align
)
401 wxDataViewRenderer::~wxDataViewRenderer()
407 wxDC
*wxDataViewRenderer::GetDC()
411 if (GetOwner() == NULL
)
413 if (GetOwner()->GetOwner() == NULL
)
415 m_dc
= new wxClientDC( GetOwner()->GetOwner() );
421 bool wxDataViewRenderer::StartEditing( unsigned int row
, wxRect labelRect
)
423 GetView()->CalcScrolledPosition( labelRect
.x
, labelRect
.y
,
424 &labelRect
.x
, &labelRect
.y
);
426 m_row
= row
; // remember for later
428 unsigned int col
= GetOwner()->GetModelColumn();
430 GetOwner()->GetOwner()->GetModel()->GetValue( value
, col
, row
);
432 m_editorCtrl
= CreateEditorCtrl( GetOwner()->GetOwner()->GetMainWindow(), labelRect
, value
);
434 m_editorCtrl
->PushEventHandler( new wxDataViewEditorCtrlEvtHandler( m_editorCtrl
, this ) );
436 m_editorCtrl
->SetFocus();
441 void wxDataViewRenderer::CancelEditing()
443 // m_editorCtrl->PopEventHandler( true );
447 GetOwner()->GetOwner()->GetMainWindow()->SetFocus();
450 bool wxDataViewRenderer::FinishEditing()
452 // m_editorCtrl->PopEventHandler( true );
455 GetValueFromEditorCtrl( m_editorCtrl
, value
);
459 GetOwner()->GetOwner()->GetMainWindow()->SetFocus();
461 if (!Validate(value
))
464 unsigned int col
= GetOwner()->GetModelColumn();
465 GetOwner()->GetOwner()->GetModel()->SetValue( value
, col
, m_row
);
466 GetOwner()->GetOwner()->GetModel()->ValueChanged( col
, m_row
);
471 //-----------------------------------------------------------------------------
472 // wxDataViewEditorCtrlEvtHandler
473 //-----------------------------------------------------------------------------
475 BEGIN_EVENT_TABLE(wxDataViewEditorCtrlEvtHandler
, wxEvtHandler
)
476 EVT_CHAR (wxDataViewEditorCtrlEvtHandler::OnChar
)
477 EVT_KILL_FOCUS (wxDataViewEditorCtrlEvtHandler::OnKillFocus
)
480 wxDataViewEditorCtrlEvtHandler::wxDataViewEditorCtrlEvtHandler(
481 wxControl
*editorCtrl
,
482 wxDataViewRenderer
*owner
)
485 m_editorCtrl
= editorCtrl
;
490 void wxDataViewEditorCtrlEvtHandler::OnChar( wxKeyEvent
&event
)
492 switch ( event
.m_keyCode
)
496 m_owner
->FinishEditing();
501 m_owner
->CancelEditing();
509 void wxDataViewEditorCtrlEvtHandler::OnKillFocus( wxFocusEvent
&event
)
514 m_owner
->FinishEditing();
517 // We must let the native text control handle focus
521 // ---------------------------------------------------------
522 // wxDataViewCustomRenderer
523 // ---------------------------------------------------------
525 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer
, wxDataViewRenderer
)
527 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString
&varianttype
,
528 wxDataViewCellMode mode
, int align
) :
529 wxDataViewRenderer( varianttype
, mode
, align
)
533 // ---------------------------------------------------------
534 // wxDataViewTextRenderer
535 // ---------------------------------------------------------
537 IMPLEMENT_CLASS(wxDataViewTextRenderer
, wxDataViewCustomRenderer
)
539 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString
&varianttype
,
540 wxDataViewCellMode mode
, int align
) :
541 wxDataViewCustomRenderer( varianttype
, mode
, align
)
545 bool wxDataViewTextRenderer::SetValue( const wxVariant
&value
)
547 m_text
= value
.GetString();
552 bool wxDataViewTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const
557 bool wxDataViewTextRenderer::HasEditorCtrl()
562 wxControl
* wxDataViewTextRenderer::CreateEditorCtrl( wxWindow
*parent
,
563 wxRect labelRect
, const wxVariant
&value
)
565 return new wxTextCtrl( parent
, wxID_ANY
, value
,
566 wxPoint(labelRect
.x
,labelRect
.y
),
567 wxSize(labelRect
.width
,labelRect
.height
) );
570 bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxControl
*editor
, wxVariant
&value
)
572 wxTextCtrl
*text
= (wxTextCtrl
*) editor
;
573 value
= text
->GetValue();
577 bool wxDataViewTextRenderer::Render( wxRect cell
, wxDC
*dc
, int state
)
579 wxDataViewCtrl
*view
= GetOwner()->GetOwner();
580 wxColour col
= (state
& wxDATAVIEW_CELL_SELECTED
) ?
581 wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) :
582 view
->GetForegroundColour();
584 dc
->SetTextForeground(col
);
585 dc
->DrawText( m_text
, cell
.x
, cell
.y
);
590 wxSize
wxDataViewTextRenderer::GetSize() const
592 const wxDataViewCtrl
*view
= GetView();
596 view
->GetTextExtent( m_text
, &x
, &y
);
597 return wxSize( x
, y
);
599 return wxSize(80,20);
602 // ---------------------------------------------------------
603 // wxDataViewBitmapRenderer
604 // ---------------------------------------------------------
606 IMPLEMENT_CLASS(wxDataViewBitmapRenderer
, wxDataViewCustomRenderer
)
608 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString
&varianttype
,
609 wxDataViewCellMode mode
, int align
) :
610 wxDataViewCustomRenderer( varianttype
, mode
, align
)
614 bool wxDataViewBitmapRenderer::SetValue( const wxVariant
&value
)
616 if (value
.GetType() == wxT("wxBitmap"))
618 if (value
.GetType() == wxT("wxIcon"))
624 bool wxDataViewBitmapRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const
629 bool wxDataViewBitmapRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
632 dc
->DrawBitmap( m_bitmap
, cell
.x
, cell
.y
);
633 else if (m_icon
.Ok())
634 dc
->DrawIcon( m_icon
, cell
.x
, cell
.y
);
639 wxSize
wxDataViewBitmapRenderer::GetSize() const
642 return wxSize( m_bitmap
.GetWidth(), m_bitmap
.GetHeight() );
643 else if (m_icon
.Ok())
644 return wxSize( m_icon
.GetWidth(), m_icon
.GetHeight() );
646 return wxSize(16,16);
649 // ---------------------------------------------------------
650 // wxDataViewToggleRenderer
651 // ---------------------------------------------------------
653 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer
, wxDataViewCustomRenderer
)
655 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString
&varianttype
,
656 wxDataViewCellMode mode
, int align
) :
657 wxDataViewCustomRenderer( varianttype
, mode
, align
)
662 bool wxDataViewToggleRenderer::SetValue( const wxVariant
&value
)
664 m_toggle
= value
.GetBool();
669 bool wxDataViewToggleRenderer::GetValue( wxVariant
&WXUNUSED(value
) ) const
674 bool wxDataViewToggleRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
676 // User wxRenderer here
679 rect
.x
= cell
.x
+ cell
.width
/2 - 10;
681 rect
.y
= cell
.y
+ cell
.height
/2 - 10;
686 flags
|= wxCONTROL_CHECKED
;
687 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE
)
688 flags
|= wxCONTROL_DISABLED
;
690 wxRendererNative::Get().DrawCheckBox(
691 GetOwner()->GetOwner(),
699 bool wxDataViewToggleRenderer::Activate( wxRect
WXUNUSED(cell
),
700 wxDataViewListModel
*model
,
701 unsigned int col
, unsigned int row
)
703 bool value
= !m_toggle
;
704 wxVariant variant
= value
;
705 model
->SetValue( variant
, col
, row
);
706 model
->ValueChanged( col
, row
);
710 wxSize
wxDataViewToggleRenderer::GetSize() const
712 return wxSize(20,20);
715 // ---------------------------------------------------------
716 // wxDataViewProgressRenderer
717 // ---------------------------------------------------------
719 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer
, wxDataViewCustomRenderer
)
721 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString
&label
,
722 const wxString
&varianttype
, wxDataViewCellMode mode
, int align
) :
723 wxDataViewCustomRenderer( varianttype
, mode
, align
)
729 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
733 bool wxDataViewProgressRenderer::SetValue( const wxVariant
&value
)
735 m_value
= (long) value
;
737 if (m_value
< 0) m_value
= 0;
738 if (m_value
> 100) m_value
= 100;
743 bool wxDataViewProgressRenderer::GetValue( wxVariant
&value
) const
745 value
= (long) m_value
;
749 bool wxDataViewProgressRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
751 double pct
= (double)m_value
/ 100.0;
753 bar
.width
= (int)(cell
.width
* pct
);
754 dc
->SetPen( *wxTRANSPARENT_PEN
);
755 dc
->SetBrush( *wxBLUE_BRUSH
);
756 dc
->DrawRectangle( bar
);
758 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
759 dc
->SetPen( *wxBLACK_PEN
);
760 dc
->DrawRectangle( cell
);
765 wxSize
wxDataViewProgressRenderer::GetSize() const
767 return wxSize(40,12);
770 // ---------------------------------------------------------
771 // wxDataViewDateRenderer
772 // ---------------------------------------------------------
774 #define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN)
776 #if wxUSE_DATE_RENDERER_POPUP
778 class wxDataViewDateRendererPopupTransient
: public wxPopupTransientWindow
781 wxDataViewDateRendererPopupTransient( wxWindow
* parent
, wxDateTime
*value
,
782 wxDataViewListModel
*model
, unsigned int col
, unsigned int row
) :
783 wxPopupTransientWindow( parent
, wxBORDER_SIMPLE
)
788 m_cal
= new wxCalendarCtrl( this, wxID_ANY
, *value
);
789 wxBoxSizer
*sizer
= new wxBoxSizer( wxHORIZONTAL
);
790 sizer
->Add( m_cal
, 1, wxGROW
);
795 void OnCalendar( wxCalendarEvent
&event
);
797 wxCalendarCtrl
*m_cal
;
798 wxDataViewListModel
*m_model
;
803 virtual void OnDismiss()
808 DECLARE_EVENT_TABLE()
811 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient
,wxPopupTransientWindow
)
812 EVT_CALENDAR( wxID_ANY
, wxDataViewDateRendererPopupTransient::OnCalendar
)
815 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent
&event
)
817 wxDateTime date
= event
.GetDate();
818 wxVariant value
= date
;
819 m_model
->SetValue( value
, m_col
, m_row
);
820 m_model
->ValueChanged( m_col
, m_row
);
824 #endif // wxUSE_DATE_RENDERER_POPUP
826 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer
, wxDataViewCustomRenderer
)
828 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString
&varianttype
,
829 wxDataViewCellMode mode
, int align
) :
830 wxDataViewCustomRenderer( varianttype
, mode
, align
)
834 bool wxDataViewDateRenderer::SetValue( const wxVariant
&value
)
836 m_date
= value
.GetDateTime();
841 bool wxDataViewDateRenderer::GetValue( wxVariant
&value
) const
847 bool wxDataViewDateRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
849 dc
->SetFont( GetOwner()->GetOwner()->GetFont() );
850 wxString tmp
= m_date
.FormatDate();
851 dc
->DrawText( tmp
, cell
.x
, cell
.y
);
856 wxSize
wxDataViewDateRenderer::GetSize() const
858 const wxDataViewCtrl
* view
= GetView();
859 wxString tmp
= m_date
.FormatDate();
861 view
->GetTextExtent( tmp
, &x
, &y
, &d
);
862 return wxSize(x
,y
+d
);
865 bool wxDataViewDateRenderer::Activate( wxRect
WXUNUSED(cell
), wxDataViewListModel
*model
,
866 unsigned int col
, unsigned int row
)
869 model
->GetValue( variant
, col
, row
);
870 wxDateTime value
= variant
.GetDateTime();
872 #if wxUSE_DATE_RENDERER_POPUP
873 wxDataViewDateRendererPopupTransient
*popup
= new wxDataViewDateRendererPopupTransient(
874 GetOwner()->GetOwner()->GetParent(), &value
, model
, col
, row
);
875 wxPoint pos
= wxGetMousePosition();
878 popup
->Popup( popup
->m_cal
);
879 #else // !wxUSE_DATE_RENDERER_POPUP
880 wxMessageBox(value
.Format());
881 #endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP
885 // ---------------------------------------------------------
887 // ---------------------------------------------------------
889 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn
, wxDataViewColumnBase
)
891 wxDataViewColumn::wxDataViewColumn( const wxString
&title
, wxDataViewRenderer
*cell
,
892 unsigned int model_column
,
893 int width
, wxAlignment align
, int flags
) :
894 wxDataViewColumnBase( title
, cell
, model_column
, width
, align
, flags
)
900 Init(width
< 0 ? wxDVC_DEFAULT_WIDTH
: width
);
903 wxDataViewColumn::wxDataViewColumn( const wxBitmap
&bitmap
, wxDataViewRenderer
*cell
,
904 unsigned int model_column
,
905 int width
, wxAlignment align
, int flags
) :
906 wxDataViewColumnBase( bitmap
, cell
, model_column
, width
, align
, flags
)
911 Init(width
< 0 ? wxDVC_TOGGLE_DEFAULT_WIDTH
: width
);
914 wxDataViewColumn::~wxDataViewColumn()
918 void wxDataViewColumn::Init( int width
)
921 m_minWidth
= wxDVC_DEFAULT_MINWIDTH
;
924 void wxDataViewColumn::SetResizeable( bool resizeable
)
927 m_flags
|= wxDATAVIEW_COL_RESIZABLE
;
929 m_flags
&= ~wxDATAVIEW_COL_RESIZABLE
;
932 void wxDataViewColumn::SetHidden( bool hidden
)
935 m_flags
|= wxDATAVIEW_COL_HIDDEN
;
937 m_flags
&= ~wxDATAVIEW_COL_HIDDEN
;
939 // tell our owner to e.g. update its scrollbars:
941 GetOwner()->OnColumnChange();
944 void wxDataViewColumn::SetSortable( bool sortable
)
947 m_flags
|= wxDATAVIEW_COL_SORTABLE
;
949 m_flags
&= ~wxDATAVIEW_COL_SORTABLE
;
952 void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending
) )
957 bool wxDataViewColumn::IsSortOrderAscending() const
963 void wxDataViewColumn::SetInternalWidth( int width
)
967 // the scrollbars of the wxDataViewCtrl needs to be recalculated!
968 if (m_owner
&& m_owner
->m_clientArea
)
969 m_owner
->m_clientArea
->RecalculateDisplay();
972 void wxDataViewColumn::SetWidth( int width
)
974 m_owner
->m_headerArea
->UpdateDisplay();
976 SetInternalWidth(width
);
980 //-----------------------------------------------------------------------------
981 // wxDataViewHeaderWindowBase
982 //-----------------------------------------------------------------------------
984 void wxDataViewHeaderWindowBase::SendEvent(wxEventType type
, unsigned int n
)
986 wxWindow
*parent
= GetParent();
987 wxDataViewEvent
le(type
, parent
->GetId());
989 le
.SetEventObject(parent
);
991 le
.SetDataViewColumn(GetColumn(n
));
992 le
.SetModel(GetOwner()->GetModel());
994 // for events created by wxDataViewHeaderWindow the
995 // row / value fields are not valid
997 parent
->GetEventHandler()->ProcessEvent(le
);
1000 #if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW
1002 // implemented in msw/listctrl.cpp:
1003 int WXDLLIMPEXP_CORE
wxMSWGetColumnClicked(NMHDR
*nmhdr
, POINT
*ptClick
);
1005 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindowMSW
, wxWindow
)
1007 bool wxDataViewHeaderWindowMSW::Create( wxDataViewCtrl
*parent
, wxWindowID id
,
1008 const wxPoint
&pos
, const wxSize
&size
,
1009 const wxString
&name
)
1013 if ( !CreateControl(parent
, id
, pos
, size
, 0, wxDefaultValidator
, name
) )
1016 int x
= pos
.x
== wxDefaultCoord
? 0 : pos
.x
,
1017 y
= pos
.y
== wxDefaultCoord
? 0 : pos
.y
,
1018 w
= size
.x
== wxDefaultCoord
? 1 : size
.x
,
1019 h
= size
.y
== wxDefaultCoord
? 22 : size
.y
;
1021 // create the native WC_HEADER window:
1022 WXHWND hwndParent
= (HWND
)parent
->GetHandle();
1023 WXDWORD msStyle
= WS_CHILD
| HDS_BUTTONS
| HDS_HORZ
| HDS_HOTTRACK
| HDS_FULLDRAG
;
1024 m_hWnd
= CreateWindowEx(0,
1035 wxLogLastError(_T("CreateWindowEx"));
1039 // we need to subclass the m_hWnd to force wxWindow::HandleNotify
1040 // to call wxDataViewHeaderWindow::MSWOnNotify
1041 SubclassWin(m_hWnd
);
1043 // the following is required to get the default win's font for
1044 // header windows and must be done befor sending the HDM_LAYOUT msg
1051 // Retrieve the bounding rectangle of the parent window's
1052 // client area, and then request size and position values
1053 // from the header control.
1054 ::GetClientRect((HWND
)hwndParent
, &rcParent
);
1056 hdl
.prc
= &rcParent
;
1058 if (!SendMessage((HWND
)m_hWnd
, HDM_LAYOUT
, 0, (LPARAM
) &hdl
))
1060 wxLogLastError(_T("SendMessage"));
1064 // Set the size, position, and visibility of the header control.
1065 SetWindowPos((HWND
)m_hWnd
,
1069 wp
.flags
| SWP_SHOWWINDOW
);
1071 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1072 // a wxBoxSizer and in order to avoid super-big header windows,
1073 // we need to set our height as fixed
1074 SetMinSize(wxSize(-1, wp
.cy
));
1075 SetMaxSize(wxSize(-1, wp
.cy
));
1080 wxDataViewHeaderWindowMSW::~wxDataViewHeaderWindow()
1085 void wxDataViewHeaderWindowMSW::UpdateDisplay()
1087 // remove old columns
1088 for (int j
=0, max
=Header_GetItemCount((HWND
)m_hWnd
); j
< max
; j
++)
1089 Header_DeleteItem((HWND
)m_hWnd
, 0);
1091 // add the updated array of columns to the header control
1092 unsigned int cols
= GetOwner()->GetColumnCount();
1093 unsigned int added
= 0;
1094 for (unsigned int i
= 0; i
< cols
; i
++)
1096 wxDataViewColumn
*col
= GetColumn( i
);
1097 if (col
->IsHidden())
1098 continue; // don't add it!
1101 hdi
.mask
= HDI_TEXT
| HDI_FORMAT
| HDI_WIDTH
;
1102 hdi
.pszText
= (wxChar
*) col
->GetTitle().wx_str();
1103 hdi
.cxy
= col
->GetWidth();
1104 hdi
.cchTextMax
= sizeof(hdi
.pszText
)/sizeof(hdi
.pszText
[0]);
1105 hdi
.fmt
= HDF_LEFT
| HDF_STRING
;
1107 // lParam is reserved for application's use:
1108 // we store there the column index to use it later in MSWOnNotify
1109 // (since columns may have been hidden)
1110 hdi
.lParam
= (LPARAM
)i
;
1112 // the native wxMSW implementation of the header window
1113 // draws the column separator COLUMN_WIDTH_OFFSET pixels
1114 // on the right: to correct this effect we make the column
1115 // exactly COLUMN_WIDTH_OFFSET wider (for the first column):
1117 hdi
.cxy
+= COLUMN_WIDTH_OFFSET
;
1119 switch (col
->GetAlignment())
1122 hdi
.fmt
|= HDF_LEFT
;
1124 case wxALIGN_CENTER
:
1125 case wxALIGN_CENTER_HORIZONTAL
:
1126 hdi
.fmt
|= HDF_CENTER
;
1129 hdi
.fmt
|= HDF_RIGHT
;
1133 // such alignment is not allowed for the column header!
1137 SendMessage((HWND
)m_hWnd
, HDM_INSERTITEM
,
1138 (WPARAM
)added
, (LPARAM
)&hdi
);
1143 unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER
*nmHDR
)
1147 // NOTE: we don't just return nmHDR->iItem because when there are
1148 // hidden columns, nmHDR->iItem may be different from
1149 // nmHDR->pitem->lParam
1151 if (nmHDR
->pitem
&& nmHDR
->pitem
->mask
& HDI_LPARAM
)
1153 idx
= (unsigned int)nmHDR
->pitem
->lParam
;
1158 item
.mask
= HDI_LPARAM
;
1159 Header_GetItem((HWND
)m_hWnd
, nmHDR
->iItem
, &item
);
1161 return (unsigned int)item
.lParam
;
1164 bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
1166 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
1168 // is it a message from the header?
1169 if ( nmhdr
->hwndFrom
!= (HWND
)m_hWnd
)
1170 return wxWindow::MSWOnNotify(idCtrl
, lParam
, result
);
1172 NMHEADER
*nmHDR
= (NMHEADER
*)nmhdr
;
1173 switch ( nmhdr
->code
)
1175 case HDN_BEGINTRACK
:
1176 // user has started to resize a column:
1177 // do we need to veto it?
1178 if (!GetColumn(nmHDR
->iItem
)->IsResizeable())
1186 // user has started to reorder a column
1189 case HDN_ITEMCHANGING
:
1190 if (nmHDR
->pitem
!= NULL
&&
1191 (nmHDR
->pitem
->mask
& HDI_WIDTH
) != 0)
1193 int minWidth
= GetColumnFromHeader(nmHDR
)->GetMinWidth();
1194 if (nmHDR
->pitem
->cxy
< minWidth
)
1196 // do not allow the user to resize this column under
1197 // its minimal width:
1203 case HDN_ITEMCHANGED
: // user is resizing a column
1204 case HDN_ENDTRACK
: // user has finished resizing a column
1205 case HDN_ENDDRAG
: // user has finished reordering a column
1207 // update the width of the modified column:
1208 if (nmHDR
->pitem
!= NULL
&&
1209 (nmHDR
->pitem
->mask
& HDI_WIDTH
) != 0)
1211 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1212 unsigned int w
= nmHDR
->pitem
->cxy
;
1213 wxDataViewColumn
*col
= GetColumn(idx
);
1215 // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET
1216 if (idx
== 0 && w
> COLUMN_WIDTH_OFFSET
)
1217 w
-= COLUMN_WIDTH_OFFSET
;
1219 if (w
>= (unsigned)col
->GetMinWidth())
1220 col
->SetInternalWidth(w
);
1226 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1227 wxEventType evt
= nmHDR
->iButton
== 0 ?
1228 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
:
1229 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
;
1230 SendEvent(evt
, idx
);
1236 // NOTE: for some reason (i.e. for a bug in Windows)
1237 // the HDN_ITEMCLICK notification is not sent on
1238 // right clicks, so we need to handle NM_RCLICK
1241 int column
= wxMSWGetColumnClicked(nmhdr
, &ptClick
);
1242 if (column
!= wxNOT_FOUND
)
1245 item
.mask
= HDI_LPARAM
;
1246 Header_GetItem((HWND
)m_hWnd
, column
, &item
);
1248 // 'idx' may be different from 'column' if there are
1249 // hidden columns...
1250 unsigned int idx
= (unsigned int)item
.lParam
;
1251 SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
,
1257 case HDN_GETDISPINFOW
:
1258 // see wxListCtrl::MSWOnNotify for more info!
1261 case HDN_ITEMDBLCLICK
:
1263 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1264 int w
= GetOwner()->GetBestColumnWidth(idx
);
1266 // update the native control:
1268 ZeroMemory(&hd
, sizeof(hd
));
1269 hd
.mask
= HDI_WIDTH
;
1271 Header_SetItem(GetHwnd(),
1272 nmHDR
->iItem
, // NOTE: we don't want 'idx' here!
1275 // update the wxDataViewColumn class:
1276 GetColumn(idx
)->SetInternalWidth(w
);
1281 return wxWindow::MSWOnNotify(idCtrl
, lParam
, result
);
1287 void wxDataViewHeaderWindowMSW::ScrollWindow(int WXUNUSED(dx
), int WXUNUSED(dy
),
1288 const wxRect
*WXUNUSED(rect
))
1290 wxSize ourSz
= GetClientSize();
1291 wxSize ownerSz
= m_owner
->GetClientSize();
1293 // where should the (logical) origin of this window be placed?
1295 m_owner
->CalcUnscrolledPosition(0, 0, &x1
, &y1
);
1297 // put this window on top of our parent and
1298 SetWindowPos((HWND
)m_hWnd
, HWND_TOP
, -x1
, 0,
1299 ownerSz
.GetWidth() + x1
, ourSz
.GetHeight(),
1303 void wxDataViewHeaderWindowMSW::DoSetSize(int WXUNUSED(x
), int WXUNUSED(y
),
1304 int WXUNUSED(w
), int WXUNUSED(h
),
1307 // the wxDataViewCtrl's internal wxBoxSizer will call this function when
1308 // the wxDataViewCtrl window gets resized: the following dummy call
1309 // to ScrollWindow() is required in order to get this header window
1310 // correctly repainted when it's (horizontally) scrolled:
1315 #else // !defined(__WXMSW__)
1317 IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow
, wxWindow
)
1318 BEGIN_EVENT_TABLE(wxGenericDataViewHeaderWindow
, wxWindow
)
1319 EVT_PAINT (wxGenericDataViewHeaderWindow::OnPaint
)
1320 EVT_MOUSE_EVENTS (wxGenericDataViewHeaderWindow::OnMouse
)
1321 EVT_SET_FOCUS (wxGenericDataViewHeaderWindow::OnSetFocus
)
1324 bool wxGenericDataViewHeaderWindow::Create(wxDataViewCtrl
*parent
, wxWindowID id
,
1325 const wxPoint
&pos
, const wxSize
&size
,
1326 const wxString
&name
)
1330 if (!wxDataViewHeaderWindowBase::Create(parent
, id
, pos
, size
, name
))
1333 wxVisualAttributes attr
= wxPanel::GetClassDefaultAttributes();
1334 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1335 SetOwnForegroundColour( attr
.colFg
);
1336 SetOwnBackgroundColour( attr
.colBg
);
1338 SetOwnFont( attr
.font
);
1340 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1341 // a wxBoxSizer and in order to avoid super-big header windows,
1342 // we need to set our height as fixed
1343 SetMinSize(wxSize(-1, HEADER_WINDOW_HEIGHT
));
1344 SetMaxSize(wxSize(-1, HEADER_WINDOW_HEIGHT
));
1349 void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1352 GetClientSize( &w
, &h
);
1354 wxAutoBufferedPaintDC
dc( this );
1356 dc
.SetBackground(GetBackgroundColour());
1360 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1363 m_owner
->GetViewStart( &x
, NULL
);
1365 // account for the horz scrollbar offset
1366 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1368 dc
.SetFont( GetFont() );
1370 unsigned int cols
= GetOwner()->GetColumnCount();
1373 for (i
= 0; i
< cols
; i
++)
1375 wxDataViewColumn
*col
= GetColumn( i
);
1376 if (col
->IsHidden())
1377 continue; // skip it!
1379 int cw
= col
->GetWidth();
1382 wxRendererNative::Get().DrawHeaderButton
1386 wxRect(xpos
, 0, cw
, ch
-1),
1387 m_parent
->IsEnabled() ? 0
1388 : (int)wxCONTROL_DISABLED
1391 // align as required the column title:
1393 wxSize titleSz
= dc
.GetTextExtent(col
->GetTitle());
1394 switch (col
->GetAlignment())
1397 x
+= HEADER_HORIZ_BORDER
;
1399 case wxALIGN_CENTER
:
1400 case wxALIGN_CENTER_HORIZONTAL
:
1401 x
+= (cw
- titleSz
.GetWidth() - 2 * HEADER_HORIZ_BORDER
)/2;
1404 x
+= cw
- titleSz
.GetWidth() - HEADER_HORIZ_BORDER
;
1408 // always center the title vertically:
1409 int y
= wxMax((ch
- titleSz
.GetHeight()) / 2, HEADER_VERT_BORDER
);
1411 dc
.SetClippingRegion( xpos
+HEADER_HORIZ_BORDER
,
1413 wxMax(cw
- 2 * HEADER_HORIZ_BORDER
, 1), // width
1414 wxMax(ch
- 2 * HEADER_VERT_BORDER
, 1)); // height
1415 dc
.DrawText( col
->GetTitle(), x
, y
);
1416 dc
.DestroyClippingRegion();
1422 void wxGenericDataViewHeaderWindow::OnSetFocus( wxFocusEvent
&event
)
1424 GetParent()->SetFocus();
1428 void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent
&event
)
1430 // we want to work with logical coords
1432 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1433 int y
= event
.GetY();
1437 // we don't draw the line beyond our window,
1438 // but we allow dragging it there
1440 GetClientSize( &w
, NULL
);
1441 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1444 // erase the line if it was drawn
1448 if (event
.ButtonUp())
1450 m_isDragging
= false;
1456 GetColumn(m_column
)->SetWidth(m_currentX
- m_minX
);
1459 GetOwner()->Refresh();
1463 m_currentX
= wxMax(m_minX
+ 7, x
);
1465 // draw in the new location
1466 if (m_currentX
< w
) DrawCurrent();
1470 else // not dragging
1473 m_column
= wxNOT_FOUND
;
1475 bool hit_border
= false;
1477 // end of the current column
1480 // find the column where this event occured
1481 int countCol
= m_owner
->GetColumnCount();
1482 for (int column
= 0; column
< countCol
; column
++)
1484 wxDataViewColumn
*p
= GetColumn(column
);
1487 continue; // skip if not shown
1489 xpos
+= p
->GetWidth();
1491 if ((abs(x
-xpos
) < 3) && (y
< 22))
1499 // inside the column
1506 if (m_column
== wxNOT_FOUND
)
1509 bool resizeable
= GetColumn(m_column
)->IsResizeable();
1510 if (event
.LeftDClick() && resizeable
)
1512 GetColumn(m_column
)->SetWidth(GetOwner()->GetBestColumnWidth(m_column
));
1515 else if (event
.LeftDown() || event
.RightUp())
1517 if (hit_border
&& event
.LeftDown() && resizeable
)
1519 m_isDragging
= true;
1524 else // click on a column
1526 wxEventType evt
= event
.LeftDown() ?
1527 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
:
1528 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
;
1529 SendEvent(evt
, m_column
);
1532 else if (event
.Moving())
1534 if (hit_border
&& resizeable
)
1535 m_currentCursor
= m_resizeCursor
;
1537 m_currentCursor
= wxSTANDARD_CURSOR
;
1539 SetCursor(*m_currentCursor
);
1544 void wxGenericDataViewHeaderWindow::DrawCurrent()
1546 int x1
= m_currentX
;
1548 ClientToScreen (&x1
, &y1
);
1550 int x2
= m_currentX
-1;
1552 ++x2
; // but why ????
1555 m_owner
->GetClientSize( NULL
, &y2
);
1556 m_owner
->ClientToScreen( &x2
, &y2
);
1559 dc
.SetLogicalFunction(wxINVERT
);
1560 dc
.SetPen(m_penCurrent
);
1561 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1563 dc
.DrawLine(x1
, y1
, x2
, y2
);
1566 void wxGenericDataViewHeaderWindow::AdjustDC(wxDC
& dc
)
1570 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1571 m_owner
->GetViewStart( &x
, NULL
);
1573 // shift the DC origin to match the position of the main window horizontal
1574 // scrollbar: this allows us to always use logical coords
1575 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1578 #endif // defined(__WXMSW__)
1580 //-----------------------------------------------------------------------------
1581 // wxDataViewRenameTimer
1582 //-----------------------------------------------------------------------------
1584 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow
*owner
)
1589 void wxDataViewRenameTimer::Notify()
1591 m_owner
->OnRenameTimer();
1594 //-----------------------------------------------------------------------------
1595 // wxDataViewMainWindow
1596 //-----------------------------------------------------------------------------
1598 int LINKAGEMODE
wxDataViewSelectionCmp( unsigned int row1
, unsigned int row2
)
1600 if (row1
> row2
) return 1;
1601 if (row1
== row2
) return 0;
1606 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
)
1608 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
)
1609 EVT_PAINT (wxDataViewMainWindow::OnPaint
)
1610 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse
)
1611 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus
)
1612 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus
)
1613 EVT_CHAR (wxDataViewMainWindow::OnChar
)
1616 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
1617 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
1618 wxWindow( parent
, id
, pos
, size
, wxWANTS_CHARS
, name
),
1619 m_selection( wxDataViewSelectionCmp
)
1624 m_lastOnSame
= false;
1625 m_renameTimer
= new wxDataViewRenameTimer( this );
1627 // TODO: user better initial values/nothing selected
1628 m_currentCol
= NULL
;
1631 // TODO: we need to calculate this smartly
1638 wxASSERT(m_lineHeight
> 2*PADDING_TOPBOTTOM
);
1641 m_dragStart
= wxPoint(0,0);
1642 m_lineLastClicked
= (unsigned int) -1;
1643 m_lineBeforeLastClicked
= (unsigned int) -1;
1644 m_lineSelectSingleOnUp
= (unsigned int) -1;
1648 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1649 SetBackgroundColour( *wxWHITE
);
1651 m_penRule
= wxPen(GetRuleColour(), 1, wxSOLID
);
1656 wxDataViewMainWindow::~wxDataViewMainWindow()
1658 delete m_renameTimer
;
1661 void wxDataViewMainWindow::OnRenameTimer()
1663 // We have to call this here because changes may just have
1664 // been made and no screen update taken place.
1670 unsigned int cols
= GetOwner()->GetColumnCount();
1672 for (i
= 0; i
< cols
; i
++)
1674 wxDataViewColumn
*c
= GetOwner()->GetColumn( i
);
1676 continue; // skip it!
1678 if (c
== m_currentCol
)
1680 xpos
+= c
->GetWidth();
1682 wxRect
labelRect( xpos
, m_currentRow
* m_lineHeight
,
1683 m_currentCol
->GetWidth(), m_lineHeight
);
1685 m_currentCol
->GetRenderer()->StartEditing( m_currentRow
, labelRect
);
1688 bool wxDataViewMainWindow::RowAppended()
1694 bool wxDataViewMainWindow::RowPrepended()
1700 bool wxDataViewMainWindow::RowInserted( unsigned int WXUNUSED(before
) )
1706 bool wxDataViewMainWindow::RowDeleted( unsigned int WXUNUSED(row
) )
1712 bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row
) )
1718 bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col
), unsigned int row
)
1720 // NOTE: to be valid, we cannot use e.g. INT_MAX - 1
1721 #define MAX_VIRTUAL_WIDTH 100000
1723 wxRect
rect( 0, row
*m_lineHeight
, MAX_VIRTUAL_WIDTH
, m_lineHeight
);
1724 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
1725 Refresh( true, &rect
);
1730 bool wxDataViewMainWindow::RowsReordered( unsigned int *WXUNUSED(new_order
) )
1736 bool wxDataViewMainWindow::Cleared()
1742 void wxDataViewMainWindow::UpdateDisplay()
1747 void wxDataViewMainWindow::OnInternalIdle()
1749 wxWindow::OnInternalIdle();
1753 RecalculateDisplay();
1758 void wxDataViewMainWindow::RecalculateDisplay()
1760 wxDataViewListModel
*model
= GetOwner()->GetModel();
1767 int width
= GetEndOfLastCol();
1768 int height
= model
->GetRowCount() * m_lineHeight
;
1770 SetVirtualSize( width
, height
);
1771 GetOwner()->SetScrollRate( 10, m_lineHeight
);
1776 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
1778 wxWindow::ScrollWindow( dx
, dy
, rect
);
1780 if (GetOwner()->m_headerArea
)
1781 GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 );
1784 void wxDataViewMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1786 wxDataViewListModel
*model
= GetOwner()->GetModel();
1787 wxAutoBufferedPaintDC
dc( this );
1790 dc
.SetBackground(GetBackgroundColour());
1792 GetOwner()->PrepareDC( dc
);
1793 dc
.SetFont( GetFont() );
1795 wxRect update
= GetUpdateRegion().GetBox();
1796 m_owner
->CalcUnscrolledPosition( update
.x
, update
.y
, &update
.x
, &update
.y
);
1798 // compute which items needs to be redrawn
1799 unsigned int item_start
= wxMax( 0, (update
.y
/ m_lineHeight
) );
1800 unsigned int item_count
=
1801 wxMin( (int)(((update
.y
+ update
.height
) / m_lineHeight
) - item_start
+ 1),
1802 (int)(model
->GetRowCount() - item_start
) );
1803 unsigned int item_last
= item_start
+ item_count
;
1805 // compute which columns needs to be redrawn
1806 unsigned int cols
= GetOwner()->GetColumnCount();
1807 unsigned int col_start
= 0;
1808 unsigned int x_start
= 0;
1809 for (x_start
= 0; col_start
< cols
; col_start
++)
1811 wxDataViewColumn
*col
= GetOwner()->GetColumn(col_start
);
1812 if (col
->IsHidden())
1813 continue; // skip it!
1815 unsigned int w
= col
->GetWidth();
1816 if (x_start
+w
>= (unsigned int)update
.x
)
1822 unsigned int col_last
= col_start
;
1823 unsigned int x_last
= x_start
;
1824 for (; col_last
< cols
; col_last
++)
1826 wxDataViewColumn
*col
= GetOwner()->GetColumn(col_last
);
1827 if (col
->IsHidden())
1828 continue; // skip it!
1830 if (x_last
> (unsigned int)update
.GetRight())
1833 x_last
+= col
->GetWidth();
1836 // Draw horizontal rules if required
1837 if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) )
1839 dc
.SetPen(m_penRule
);
1840 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1842 for (unsigned int i
= item_start
; i
<= item_last
+1; i
++)
1844 int y
= i
* m_lineHeight
;
1845 dc
.DrawLine(x_start
, y
, x_last
, y
);
1849 // Draw vertical rules if required
1850 if ( m_owner
->HasFlag(wxDV_VERT_RULES
) )
1852 dc
.SetPen(m_penRule
);
1853 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1856 for (unsigned int i
= col_start
; i
< col_last
; i
++)
1858 wxDataViewColumn
*col
= GetOwner()->GetColumn(i
);
1859 if (col
->IsHidden())
1860 continue; // skip it
1862 dc
.DrawLine(x
, item_start
* m_lineHeight
,
1863 x
, item_last
* m_lineHeight
);
1865 x
+= col
->GetWidth();
1868 // Draw last vertical rule
1869 dc
.DrawLine(x
, item_start
* m_lineHeight
,
1870 x
, item_last
* m_lineHeight
);
1873 // redraw the background for the items which are selected/current
1874 for (unsigned int item
= item_start
; item
< item_last
; item
++)
1876 bool selected
= m_selection
.Index( item
) != wxNOT_FOUND
;
1877 if (selected
|| item
== m_currentRow
)
1879 int flags
= selected
? (int)wxCONTROL_SELECTED
: 0;
1880 if (item
== m_currentRow
)
1881 flags
|= wxCONTROL_CURRENT
;
1883 flags
|= wxCONTROL_FOCUSED
;
1885 wxRect
rect( x_start
, item
*m_lineHeight
, x_last
, m_lineHeight
);
1886 wxRendererNative::Get().DrawItemSelectionRect
1896 // redraw all cells for all rows which must be repainted and for all columns
1898 cell_rect
.x
= x_start
;
1899 cell_rect
.height
= m_lineHeight
; // -1 is for the horizontal rules
1900 for (unsigned int i
= col_start
; i
< col_last
; i
++)
1902 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
1903 wxDataViewRenderer
*cell
= col
->GetRenderer();
1904 cell_rect
.width
= col
->GetWidth();
1906 if (col
->IsHidden())
1907 continue; // skipt it!
1909 for (unsigned int item
= item_start
; item
< item_last
; item
++)
1911 // get the cell value and set it into the renderer
1913 model
->GetValue( value
, col
->GetModelColumn(), item
);
1914 cell
->SetValue( value
);
1916 // update the y offset
1917 cell_rect
.y
= item
* m_lineHeight
;
1919 // cannot be bigger than allocated space
1920 wxSize size
= cell
->GetSize();
1921 size
.x
= wxMin( size
.x
+ 2*PADDING_RIGHTLEFT
, cell_rect
.width
);
1922 size
.y
= wxMin( size
.y
+ 2*PADDING_TOPBOTTOM
, cell_rect
.height
);
1924 wxRect
item_rect(cell_rect
.GetTopLeft(), size
);
1925 int align
= cell
->GetAlignment();
1927 // horizontal alignment:
1928 item_rect
.x
= cell_rect
.x
;
1929 if (align
& wxALIGN_CENTER_HORIZONTAL
)
1930 item_rect
.x
= cell_rect
.x
+ (cell_rect
.width
/ 2) - (size
.x
/ 2);
1931 else if (align
& wxALIGN_RIGHT
)
1932 item_rect
.x
= cell_rect
.x
+ cell_rect
.width
- size
.x
;
1933 //else: wxALIGN_LEFT is the default
1935 // vertical alignment:
1936 item_rect
.y
= cell_rect
.y
;
1937 if (align
& wxALIGN_CENTER_VERTICAL
)
1938 item_rect
.y
= cell_rect
.y
+ (cell_rect
.height
/ 2) - (size
.y
/ 2);
1939 else if (align
& wxALIGN_BOTTOM
)
1940 item_rect
.y
= cell_rect
.y
+ cell_rect
.height
- size
.y
;
1941 //else: wxALIGN_TOP is the default
1944 item_rect
.x
+= PADDING_RIGHTLEFT
;
1945 item_rect
.y
+= PADDING_TOPBOTTOM
;
1946 item_rect
.width
= size
.x
- 2 * PADDING_RIGHTLEFT
;
1947 item_rect
.height
= size
.y
- 2 * PADDING_TOPBOTTOM
;
1950 if (m_selection
.Index(item
) != wxNOT_FOUND
)
1951 state
|= wxDATAVIEW_CELL_SELECTED
;
1953 // TODO: it would be much more efficient to create a clipping
1954 // region for the entire column being rendered (in the OnPaint
1955 // of wxDataViewMainWindow) instead of a single clip region for
1956 // each cell. However it would mean that each renderer should
1957 // respect the given wxRect's top & bottom coords, eventually
1958 // violating only the left & right coords - however the user can
1959 // make its own renderer and thus we cannot be sure of that.
1960 dc
.SetClippingRegion( item_rect
);
1961 cell
->Render( item_rect
, &dc
, state
);
1962 dc
.DestroyClippingRegion();
1965 cell_rect
.x
+= cell_rect
.width
;
1969 int wxDataViewMainWindow::GetCountPerPage() const
1971 wxSize size
= GetClientSize();
1972 return size
.y
/ m_lineHeight
;
1975 int wxDataViewMainWindow::GetEndOfLastCol() const
1979 for (i
= 0; i
< GetOwner()->GetColumnCount(); i
++)
1981 const wxDataViewColumn
*c
=
1982 wx_const_cast(wxDataViewCtrl
*, GetOwner())->GetColumn( i
);
1985 width
+= c
->GetWidth();
1990 unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const
1994 m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y
);
1996 return y
/ m_lineHeight
;
1999 unsigned int wxDataViewMainWindow::GetLastVisibleRow() const
2001 wxSize client_size
= GetClientSize();
2002 m_owner
->CalcUnscrolledPosition( client_size
.x
, client_size
.y
,
2003 &client_size
.x
, &client_size
.y
);
2005 return wxMin( GetRowCount()-1, ((unsigned)client_size
.y
/m_lineHeight
)+1 );
2008 unsigned int wxDataViewMainWindow::GetRowCount() const
2010 return wx_const_cast(wxDataViewCtrl
*, GetOwner())->GetModel()->GetRowCount();
2013 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row
)
2020 void wxDataViewMainWindow::SelectAllRows( bool on
)
2027 m_selection
.Clear();
2028 for (unsigned int i
= 0; i
< GetRowCount(); i
++)
2029 m_selection
.Add( i
);
2034 unsigned int first_visible
= GetFirstVisibleRow();
2035 unsigned int last_visible
= GetLastVisibleRow();
2037 for (i
= 0; i
< m_selection
.GetCount(); i
++)
2039 unsigned int row
= m_selection
[i
];
2040 if ((row
>= first_visible
) && (row
<= last_visible
))
2043 m_selection
.Clear();
2047 void wxDataViewMainWindow::SelectRow( unsigned int row
, bool on
)
2049 if (m_selection
.Index( row
) == wxNOT_FOUND
)
2053 m_selection
.Add( row
);
2061 m_selection
.Remove( row
);
2067 void wxDataViewMainWindow::SelectRows( unsigned int from
, unsigned int to
, bool on
)
2071 unsigned int tmp
= from
;
2077 for (i
= from
; i
<= to
; i
++)
2079 if (m_selection
.Index( i
) == wxNOT_FOUND
)
2082 m_selection
.Add( i
);
2087 m_selection
.Remove( i
);
2090 RefreshRows( from
, to
);
2093 void wxDataViewMainWindow::Select( const wxArrayInt
& aSelections
)
2095 for (size_t i
=0; i
< aSelections
.GetCount(); i
++)
2097 int n
= aSelections
[i
];
2099 m_selection
.Add( n
);
2104 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row
)
2106 if (m_selection
.Index( row
) == wxNOT_FOUND
)
2107 m_selection
.Add( row
);
2109 m_selection
.Remove( row
);
2113 bool wxDataViewMainWindow::IsRowSelected( unsigned int row
)
2115 return (m_selection
.Index( row
) != wxNOT_FOUND
);
2118 void wxDataViewMainWindow::RefreshRow( unsigned int row
)
2120 wxRect
rect( 0, row
*m_lineHeight
, GetEndOfLastCol(), m_lineHeight
);
2121 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2123 wxSize client_size
= GetClientSize();
2124 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
2125 wxRect intersect_rect
= client_rect
.Intersect( rect
);
2126 if (intersect_rect
.width
> 0)
2127 Refresh( true, &intersect_rect
);
2130 void wxDataViewMainWindow::RefreshRows( unsigned int from
, unsigned int to
)
2134 unsigned int tmp
= to
;
2139 wxRect
rect( 0, from
*m_lineHeight
, GetEndOfLastCol(), (to
-from
+1) * m_lineHeight
);
2140 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2142 wxSize client_size
= GetClientSize();
2143 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
2144 wxRect intersect_rect
= client_rect
.Intersect( rect
);
2145 if (intersect_rect
.width
> 0)
2146 Refresh( true, &intersect_rect
);
2149 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow
)
2151 unsigned int count
= GetRowCount();
2152 if (firstRow
> count
)
2155 wxRect
rect( 0, firstRow
*m_lineHeight
, GetEndOfLastCol(), count
* m_lineHeight
);
2156 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2158 wxSize client_size
= GetClientSize();
2159 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
2160 wxRect intersect_rect
= client_rect
.Intersect( rect
);
2161 if (intersect_rect
.width
> 0)
2162 Refresh( true, &intersect_rect
);
2165 void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
)
2167 wxCHECK_RET( newCurrent
< GetRowCount(),
2168 _T("invalid item index in OnArrowChar()") );
2170 // if there is no selection, we cannot move it anywhere
2171 if (!HasCurrentRow())
2174 unsigned int oldCurrent
= m_currentRow
;
2176 // in single selection we just ignore Shift as we can't select several
2178 if ( event
.ShiftDown() && !IsSingleSel() )
2180 RefreshRow( oldCurrent
);
2182 ChangeCurrentRow( newCurrent
);
2184 // select all the items between the old and the new one
2185 if ( oldCurrent
> newCurrent
)
2187 newCurrent
= oldCurrent
;
2188 oldCurrent
= m_currentRow
;
2191 SelectRows( oldCurrent
, newCurrent
, true );
2195 RefreshRow( oldCurrent
);
2197 // all previously selected items are unselected unless ctrl is held
2198 if ( !event
.ControlDown() )
2199 SelectAllRows(false);
2201 ChangeCurrentRow( newCurrent
);
2203 if ( !event
.ControlDown() )
2204 SelectRow( m_currentRow
, true );
2206 RefreshRow( m_currentRow
);
2209 //EnsureVisible( m_currentRow );
2212 wxRect
wxDataViewMainWindow::GetLineRect( unsigned int row
) const
2216 rect
.y
= m_lineHeight
* row
;
2217 rect
.width
= GetEndOfLastCol();
2218 rect
.height
= m_lineHeight
;
2223 void wxDataViewMainWindow::OnChar( wxKeyEvent
&event
)
2225 if (event
.GetKeyCode() == WXK_TAB
)
2227 wxNavigationKeyEvent nevent
;
2228 nevent
.SetWindowChange( event
.ControlDown() );
2229 nevent
.SetDirection( !event
.ShiftDown() );
2230 nevent
.SetEventObject( GetParent()->GetParent() );
2231 nevent
.SetCurrentFocus( m_parent
);
2232 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
))
2236 // no item -> nothing to do
2237 if (!HasCurrentRow())
2243 // don't use m_linesPerPage directly as it might not be computed yet
2244 const int pageSize
= GetCountPerPage();
2245 wxCHECK_RET( pageSize
, _T("should have non zero page size") );
2247 switch ( event
.GetKeyCode() )
2250 if ( m_currentRow
> 0 )
2251 OnArrowChar( m_currentRow
- 1, event
);
2255 if ( m_currentRow
< GetRowCount() - 1 )
2256 OnArrowChar( m_currentRow
+ 1, event
);
2261 OnArrowChar( GetRowCount() - 1, event
);
2266 OnArrowChar( 0, event
);
2271 int steps
= pageSize
- 1;
2272 int index
= m_currentRow
- steps
;
2276 OnArrowChar( index
, event
);
2282 int steps
= pageSize
- 1;
2283 unsigned int index
= m_currentRow
+ steps
;
2284 unsigned int count
= GetRowCount();
2285 if ( index
>= count
)
2288 OnArrowChar( index
, event
);
2297 void wxDataViewMainWindow::OnMouse( wxMouseEvent
&event
)
2299 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
2301 // let the base handle mouse wheel events.
2306 int x
= event
.GetX();
2307 int y
= event
.GetY();
2308 m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y
);
2310 wxDataViewColumn
*col
= NULL
;
2313 unsigned int cols
= GetOwner()->GetColumnCount();
2315 for (i
= 0; i
< cols
; i
++)
2317 wxDataViewColumn
*c
= GetOwner()->GetColumn( i
);
2319 continue; // skip it!
2321 if (x
< xpos
+ c
->GetWidth())
2326 xpos
+= c
->GetWidth();
2330 wxDataViewRenderer
*cell
= col
->GetRenderer();
2332 unsigned int current
= y
/ m_lineHeight
;
2334 if ((current
> GetRowCount()) || (x
> GetEndOfLastCol()))
2336 // Unselect all if below the last row ?
2340 wxDataViewListModel
*model
= GetOwner()->GetModel();
2342 if (event
.Dragging())
2344 if (m_dragCount
== 0)
2346 // we have to report the raw, physical coords as we want to be
2347 // able to call HitTest(event.m_pointDrag) from the user code to
2348 // get the item being dragged
2349 m_dragStart
= event
.GetPosition();
2354 if (m_dragCount
!= 3)
2357 if (event
.LeftIsDown())
2359 // Notify cell about drag
2368 bool forceClick
= false;
2370 if (event
.ButtonDClick())
2372 m_renameTimer
->Stop();
2373 m_lastOnSame
= false;
2376 if (event
.LeftDClick())
2378 if ( current
== m_lineLastClicked
)
2380 if (cell
->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE
)
2383 model
->GetValue( value
, col
->GetModelColumn(), current
);
2384 cell
->SetValue( value
);
2385 wxRect
cell_rect( xpos
, current
* m_lineHeight
,
2386 col
->GetWidth(), m_lineHeight
);
2387 cell
->Activate( cell_rect
, model
, col
->GetModelColumn(), current
);
2393 // The first click was on another item, so don't interpret this as
2394 // a double click, but as a simple click instead
2401 if (m_lineSelectSingleOnUp
!= (unsigned int)-1)
2403 // select single line
2404 SelectAllRows( false );
2405 SelectRow( m_lineSelectSingleOnUp
, true );
2410 if ((col
== m_currentCol
) && (current
== m_currentRow
) &&
2411 (cell
->GetMode() == wxDATAVIEW_CELL_EDITABLE
) )
2413 m_renameTimer
->Start( 100, true );
2417 m_lastOnSame
= false;
2418 m_lineSelectSingleOnUp
= (unsigned int)-1;
2422 // This is necessary, because after a DnD operation in
2423 // from and to ourself, the up event is swallowed by the
2424 // DnD code. So on next non-up event (which means here and
2425 // now) m_lineSelectSingleOnUp should be reset.
2426 m_lineSelectSingleOnUp
= (unsigned int)-1;
2429 if (event
.RightDown())
2431 m_lineBeforeLastClicked
= m_lineLastClicked
;
2432 m_lineLastClicked
= current
;
2434 // If the item is already selected, do not update the selection.
2435 // Multi-selections should not be cleared if a selected item is clicked.
2436 if (!IsRowSelected(current
))
2438 SelectAllRows(false);
2439 ChangeCurrentRow(current
);
2440 SelectRow(m_currentRow
,true);
2443 // notify cell about right click
2446 // Allow generation of context menu event
2449 else if (event
.MiddleDown())
2451 // notify cell about middle click
2454 if (event
.LeftDown() || forceClick
)
2460 m_lineBeforeLastClicked
= m_lineLastClicked
;
2461 m_lineLastClicked
= current
;
2463 unsigned int oldCurrentRow
= m_currentRow
;
2464 bool oldWasSelected
= IsRowSelected(m_currentRow
);
2466 bool cmdModifierDown
= event
.CmdDown();
2467 if ( IsSingleSel() || !(cmdModifierDown
|| event
.ShiftDown()) )
2469 if ( IsSingleSel() || !IsRowSelected(current
) )
2471 SelectAllRows( false );
2473 ChangeCurrentRow(current
);
2475 SelectRow(m_currentRow
,true);
2477 else // multi sel & current is highlighted & no mod keys
2479 m_lineSelectSingleOnUp
= current
;
2480 ChangeCurrentRow(current
); // change focus
2483 else // multi sel & either ctrl or shift is down
2485 if (cmdModifierDown
)
2487 ChangeCurrentRow(current
);
2489 ReverseRowSelection(m_currentRow
);
2491 else if (event
.ShiftDown())
2493 ChangeCurrentRow(current
);
2495 unsigned int lineFrom
= oldCurrentRow
,
2498 if ( lineTo
< lineFrom
)
2501 lineFrom
= m_currentRow
;
2504 SelectRows(lineFrom
, lineTo
, true);
2506 else // !ctrl, !shift
2508 // test in the enclosing if should make it impossible
2509 wxFAIL_MSG( _T("how did we get here?") );
2513 if (m_currentRow
!= oldCurrentRow
)
2514 RefreshRow( oldCurrentRow
);
2516 wxDataViewColumn
*oldCurrentCol
= m_currentCol
;
2518 // Update selection here...
2521 m_lastOnSame
= !forceClick
&& ((col
== oldCurrentCol
) &&
2522 (current
== oldCurrentRow
)) && oldWasSelected
;
2526 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent
&event
)
2530 if (HasCurrentRow())
2536 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent
&event
)
2540 if (HasCurrentRow())
2546 //-----------------------------------------------------------------------------
2548 //-----------------------------------------------------------------------------
2550 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
)
2552 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
)
2553 EVT_SIZE(wxDataViewCtrl::OnSize
)
2556 wxDataViewCtrl::~wxDataViewCtrl()
2559 GetModel()->RemoveNotifier( m_notifier
);
2562 void wxDataViewCtrl::Init()
2567 bool wxDataViewCtrl::Create(wxWindow
*parent
, wxWindowID id
,
2568 const wxPoint
& pos
, const wxSize
& size
,
2569 long style
, const wxValidator
& validator
)
2571 if (!wxControl::Create( parent
, id
, pos
, size
,
2572 style
| wxScrolledWindowStyle
|wxSUNKEN_BORDER
, validator
))
2578 MacSetClipChildren( true ) ;
2581 m_clientArea
= new wxDataViewMainWindow( this, wxID_ANY
);
2583 if (HasFlag(wxDV_NO_HEADER
))
2584 m_headerArea
= NULL
;
2586 m_headerArea
= new wxDataViewHeaderWindow( this, wxID_ANY
);
2588 SetTargetWindow( m_clientArea
);
2590 wxBoxSizer
*sizer
= new wxBoxSizer( wxVERTICAL
);
2592 sizer
->Add( m_headerArea
, 0, wxGROW
);
2593 sizer
->Add( m_clientArea
, 1, wxGROW
);
2600 WXLRESULT
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
,
2604 WXLRESULT rc
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
);
2607 // we need to process arrows ourselves for scrolling
2608 if ( nMsg
== WM_GETDLGCODE
)
2610 rc
|= DLGC_WANTARROWS
;
2618 void wxDataViewCtrl::OnSize( wxSizeEvent
&WXUNUSED(event
) )
2620 // We need to override OnSize so that our scrolled
2621 // window a) does call Layout() to use sizers for
2622 // positioning the controls but b) does not query
2623 // the sizer for their size and use that for setting
2624 // the scrollable area as set that ourselves by
2625 // calling SetScrollbar() further down.
2632 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel
*model
)
2634 if (!wxDataViewCtrlBase::AssociateModel( model
))
2637 m_notifier
= new wxGenericDataViewListModelNotifier( m_clientArea
);
2639 model
->AddNotifier( m_notifier
);
2641 m_clientArea
->UpdateDisplay();
2646 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn
*col
)
2648 if (!wxDataViewCtrlBase::AppendColumn(col
))
2655 void wxDataViewCtrl::OnColumnChange()
2658 m_headerArea
->UpdateDisplay();
2660 m_clientArea
->UpdateDisplay();
2663 void wxDataViewCtrl::SetSelection( int row
)
2665 m_clientArea
->SelectRow(row
, true);
2668 void wxDataViewCtrl::SetSelectionRange( unsigned int from
, unsigned int to
)
2670 m_clientArea
->SelectRows(from
, to
, true);
2673 void wxDataViewCtrl::SetSelections( const wxArrayInt
& aSelections
)
2675 m_clientArea
->Select(aSelections
);
2678 void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row
) )
2683 bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row
) ) const
2690 int wxDataViewCtrl::GetSelection() const
2697 int wxDataViewCtrl::GetSelections(wxArrayInt
& WXUNUSED(aSelections
) ) const
2705 // !wxUSE_GENERICDATAVIEWCTRL
2708 // wxUSE_DATAVIEWCTRL