1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/datavgen.cpp
3 // Purpose: wxDataViewCtrl generic implementation
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
13 #if wxUSE_DATAVIEWCTRL
15 #include "wx/dataview.h"
17 #ifdef wxUSE_GENERICDATAVIEWCTRL
24 #include "wx/stockitem.h"
25 #include "wx/dcclient.h"
26 #include "wx/calctrl.h"
27 #include "wx/popupwin.h"
28 #include "wx/renderer.h"
30 #include "wx/settings.h"
33 #include "wx/msw/wrapwin.h"
36 //-----------------------------------------------------------------------------
38 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
43 // wxDataViewHeaderWindow
44 //-----------------------------------------------------------------------------
46 class wxDataViewHeaderWindow
: public wxWindow
49 wxDataViewHeaderWindow( wxDataViewCtrl
*parent
,
51 const wxPoint
&pos
= wxDefaultPosition
,
52 const wxSize
&size
= wxDefaultSize
,
53 const wxString
&name
= wxT("wxdataviewctrlheaderwindow") );
54 ~wxDataViewHeaderWindow();
56 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
57 wxDataViewCtrl
*GetOwner() { return m_owner
; }
59 void OnPaint( wxPaintEvent
&event
);
60 void OnMouse( wxMouseEvent
&event
);
61 void OnSetFocus( wxFocusEvent
&event
);
64 wxDataViewCtrl
*m_owner
;
65 wxCursor
*m_resizeCursor
;
68 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow
)
72 //-----------------------------------------------------------------------------
73 // wxDataViewRenameTimer
74 //-----------------------------------------------------------------------------
76 class wxDataViewRenameTimer
: public wxTimer
79 wxDataViewMainWindow
*m_owner
;
82 wxDataViewRenameTimer( wxDataViewMainWindow
*owner
);
86 //-----------------------------------------------------------------------------
87 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
88 //-----------------------------------------------------------------------------
90 class wxDataViewTextCtrlWrapper
: public wxEvtHandler
93 // NB: text must be a valid object but not Create()d yet
94 wxDataViewTextCtrlWrapper( wxDataViewMainWindow
*owner
,
96 wxDataViewListModel
*model
,
97 size_t col
, size_t row
,
100 wxTextCtrl
*GetText() const { return m_text
; }
102 void AcceptChangesAndFinish();
105 void OnChar( wxKeyEvent
&event
);
106 void OnKeyUp( wxKeyEvent
&event
);
107 void OnKillFocus( wxFocusEvent
&event
);
109 bool AcceptChanges();
113 wxDataViewMainWindow
*m_owner
;
115 wxString m_startValue
;
116 wxDataViewListModel
*m_model
;
120 bool m_aboutToFinish
;
122 DECLARE_EVENT_TABLE()
125 //-----------------------------------------------------------------------------
126 // wxDataViewMainWindow
127 //-----------------------------------------------------------------------------
129 WX_DEFINE_SORTED_ARRAY_SIZE_T( size_t, wxDataViewSelection
);
131 class wxDataViewMainWindow
: public wxWindow
134 wxDataViewMainWindow( wxDataViewCtrl
*parent
,
136 const wxPoint
&pos
= wxDefaultPosition
,
137 const wxSize
&size
= wxDefaultSize
,
138 const wxString
&name
= wxT("wxdataviewctrlmainwindow") );
139 ~wxDataViewMainWindow();
141 // notifications from wxDataViewListModel
144 bool RowInserted( size_t before
);
145 bool RowDeleted( size_t row
);
146 bool RowChanged( size_t row
);
147 bool ValueChanged( size_t col
, size_t row
);
148 bool RowsReordered( size_t *new_order
);
151 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
152 wxDataViewCtrl
*GetOwner() { return m_owner
; }
154 void OnPaint( wxPaintEvent
&event
);
155 void OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
);
156 void OnChar( wxKeyEvent
&event
);
157 void OnMouse( wxMouseEvent
&event
);
158 void OnSetFocus( wxFocusEvent
&event
);
159 void OnKillFocus( wxFocusEvent
&event
);
161 void UpdateDisplay();
162 void RecalculateDisplay();
163 void OnInternalIdle();
165 void OnRenameTimer();
166 void FinishEditing( wxTextCtrl
*text
);
168 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
);
170 bool HasCurrentRow() { return m_currentRow
!= (size_t)-1; }
172 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE
); };
173 bool IsEmpty() { return GetRowCount() == 0; }
175 int GetCountPerPage();
178 void SelectAllRows( bool on
);
179 void SelectRow( size_t row
, bool on
);
180 void SelectRows( size_t from
, size_t to
, bool on
);
181 void ReverseRowSelection( size_t row
);
182 bool IsRowSelected( size_t row
);
184 void RefreshRow( size_t row
);
185 void RefreshRows( size_t from
, size_t to
);
186 void RefreshRowsAfter( size_t firstRow
);
189 wxDataViewCtrl
*m_owner
;
193 wxDataViewColumn
*m_currentCol
;
195 wxDataViewSelection m_selection
;
197 wxDataViewRenameTimer
*m_renameTimer
;
198 wxDataViewTextCtrlWrapper
*m_textctrlWrapper
;
201 wxBrush
*m_highlightBrush
,
202 *m_highlightUnfocusedBrush
;
207 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
)
208 DECLARE_EVENT_TABLE()
211 // ---------------------------------------------------------
212 // wxGenericDataViewListModelNotifier
213 // ---------------------------------------------------------
215 class wxGenericDataViewListModelNotifier
: public wxDataViewListModelNotifier
218 wxGenericDataViewListModelNotifier( wxDataViewMainWindow
*mainWindow
)
219 { m_mainWindow
= mainWindow
; }
221 virtual bool RowAppended()
222 { return m_mainWindow
->RowAppended(); }
223 virtual bool RowPrepended()
224 { return m_mainWindow
->RowPrepended(); }
225 virtual bool RowInserted( size_t before
)
226 { return m_mainWindow
->RowInserted( before
); }
227 virtual bool RowDeleted( size_t row
)
228 { return m_mainWindow
->RowDeleted( row
); }
229 virtual bool RowChanged( size_t row
)
230 { return m_mainWindow
->RowChanged( row
); }
231 virtual bool ValueChanged( size_t col
, size_t row
)
232 { return m_mainWindow
->ValueChanged( col
, row
); }
233 virtual bool RowsReordered( size_t *new_order
)
234 { return m_mainWindow
->RowsReordered( new_order
); }
235 virtual bool Cleared()
236 { return m_mainWindow
->Cleared(); }
238 wxDataViewMainWindow
*m_mainWindow
;
241 // ---------------------------------------------------------
243 // ---------------------------------------------------------
245 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCell
, wxDataViewCellBase
)
247 wxDataViewCell::wxDataViewCell( const wxString
&varianttype
, wxDataViewCellMode mode
) :
248 wxDataViewCellBase( varianttype
, mode
)
253 wxDataViewCell::~wxDataViewCell()
259 wxDC
*wxDataViewCell::GetDC()
263 if (GetOwner() == NULL
)
265 if (GetOwner()->GetOwner() == NULL
)
267 m_dc
= new wxClientDC( GetOwner()->GetOwner() );
273 // ---------------------------------------------------------
274 // wxDataViewCustomCell
275 // ---------------------------------------------------------
277 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomCell
, wxDataViewCell
)
279 wxDataViewCustomCell::wxDataViewCustomCell( const wxString
&varianttype
,
280 wxDataViewCellMode mode
) :
281 wxDataViewCell( varianttype
, mode
)
285 // ---------------------------------------------------------
286 // wxDataViewTextCell
287 // ---------------------------------------------------------
289 IMPLEMENT_ABSTRACT_CLASS(wxDataViewTextCell
, wxDataViewCustomCell
)
291 wxDataViewTextCell::wxDataViewTextCell( const wxString
&varianttype
, wxDataViewCellMode mode
) :
292 wxDataViewCustomCell( varianttype
, mode
)
296 bool wxDataViewTextCell::SetValue( const wxVariant
&value
)
298 m_text
= value
.GetString();
303 bool wxDataViewTextCell::GetValue( wxVariant
& WXUNUSED(value
) )
308 bool wxDataViewTextCell::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
310 dc
->DrawText( m_text
, cell
.x
, cell
.y
);
315 wxSize
wxDataViewTextCell::GetSize()
317 return wxSize(80,20);
320 // ---------------------------------------------------------
321 // wxDataViewToggleCell
322 // ---------------------------------------------------------
324 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleCell
, wxDataViewCustomCell
)
326 wxDataViewToggleCell::wxDataViewToggleCell( const wxString
&varianttype
,
327 wxDataViewCellMode mode
) :
328 wxDataViewCustomCell( varianttype
, mode
)
333 bool wxDataViewToggleCell::SetValue( const wxVariant
&value
)
335 m_toggle
= value
.GetBool();
340 bool wxDataViewToggleCell::GetValue( wxVariant
&WXUNUSED(value
) )
345 bool wxDataViewToggleCell::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
347 // User wxRenderer here
350 rect
.x
= cell
.x
+ cell
.width
/2 - 10;
352 rect
.y
= cell
.y
+ cell
.height
/2 - 10;
357 flags
|= wxCONTROL_CHECKED
;
358 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE
)
359 flags
|= wxCONTROL_DISABLED
;
361 wxRendererNative::Get().DrawCheckButton(
362 GetOwner()->GetOwner(),
370 bool wxDataViewToggleCell::Activate( wxRect
WXUNUSED(cell
), wxDataViewListModel
*model
, size_t col
, size_t row
)
372 bool value
= !m_toggle
;
373 wxVariant variant
= value
;
374 model
->SetValue( variant
, col
, row
);
375 model
->ValueChanged( col
, row
);
379 wxSize
wxDataViewToggleCell::GetSize()
381 return wxSize(20,20);
384 // ---------------------------------------------------------
385 // wxDataViewProgressCell
386 // ---------------------------------------------------------
388 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressCell
, wxDataViewCustomCell
)
390 wxDataViewProgressCell::wxDataViewProgressCell( const wxString
&label
,
391 const wxString
&varianttype
, wxDataViewCellMode mode
) :
392 wxDataViewCustomCell( varianttype
, mode
)
398 wxDataViewProgressCell::~wxDataViewProgressCell()
402 bool wxDataViewProgressCell::SetValue( const wxVariant
&value
)
404 m_value
= (long) value
;
406 if (m_value
< 0) m_value
= 0;
407 if (m_value
> 100) m_value
= 100;
412 bool wxDataViewProgressCell::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
414 double pct
= (double)m_value
/ 100.0;
416 bar
.width
= (int)(cell
.width
* pct
);
417 dc
->SetPen( *wxTRANSPARENT_PEN
);
418 dc
->SetBrush( *wxBLUE_BRUSH
);
419 dc
->DrawRectangle( bar
);
421 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
422 dc
->SetPen( *wxBLACK_PEN
);
423 dc
->DrawRectangle( cell
);
428 wxSize
wxDataViewProgressCell::GetSize()
430 return wxSize(40,12);
433 // ---------------------------------------------------------
434 // wxDataViewDateCell
435 // ---------------------------------------------------------
437 class wxDataViewDateCellPopupTransient
: public wxPopupTransientWindow
440 wxDataViewDateCellPopupTransient( wxWindow
* parent
, wxDateTime
*value
,
441 wxDataViewListModel
*model
, size_t col
, size_t row
) :
442 wxPopupTransientWindow( parent
, wxBORDER_SIMPLE
)
447 m_cal
= new wxCalendarCtrl( this, wxID_ANY
, *value
);
448 wxBoxSizer
*sizer
= new wxBoxSizer( wxHORIZONTAL
);
449 sizer
->Add( m_cal
, 1, wxGROW
);
454 virtual void OnDismiss()
458 void OnCalendar( wxCalendarEvent
&event
);
460 wxCalendarCtrl
*m_cal
;
461 wxDataViewListModel
*m_model
;
466 DECLARE_EVENT_TABLE()
469 BEGIN_EVENT_TABLE(wxDataViewDateCellPopupTransient
,wxPopupTransientWindow
)
470 EVT_CALENDAR( wxID_ANY
, wxDataViewDateCellPopupTransient::OnCalendar
)
473 void wxDataViewDateCellPopupTransient::OnCalendar( wxCalendarEvent
&event
)
475 wxDateTime date
= event
.GetDate();
476 wxVariant value
= date
;
477 m_model
->SetValue( value
, m_col
, m_row
);
478 m_model
->ValueChanged( m_col
, m_row
);
482 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateCell
, wxDataViewCustomCell
)
484 wxDataViewDateCell::wxDataViewDateCell( const wxString
&varianttype
,
485 wxDataViewCellMode mode
) :
486 wxDataViewCustomCell( varianttype
, mode
)
490 bool wxDataViewDateCell::SetValue( const wxVariant
&value
)
492 m_date
= value
.GetDateTime();
497 bool wxDataViewDateCell::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
499 dc
->SetFont( GetOwner()->GetOwner()->GetFont() );
500 wxString tmp
= m_date
.FormatDate();
501 dc
->DrawText( tmp
, cell
.x
, cell
.y
);
506 wxSize
wxDataViewDateCell::GetSize()
508 wxDataViewCtrl
* view
= GetOwner()->GetOwner();
509 wxString tmp
= m_date
.FormatDate();
511 view
->GetTextExtent( tmp
, &x
, &y
, &d
);
512 return wxSize(x
,y
+d
);
515 bool wxDataViewDateCell::Activate( wxRect
WXUNUSED(cell
), wxDataViewListModel
*model
, size_t col
, size_t row
)
518 model
->GetValue( variant
, col
, row
);
519 wxDateTime value
= variant
.GetDateTime();
521 wxDataViewDateCellPopupTransient
*popup
= new wxDataViewDateCellPopupTransient(
522 GetOwner()->GetOwner()->GetParent(), &value
, model
, col
, row
);
523 wxPoint pos
= wxGetMousePosition();
526 popup
->Popup( popup
->m_cal
);
531 // ---------------------------------------------------------
533 // ---------------------------------------------------------
535 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn
, wxDataViewColumnBase
)
537 wxDataViewColumn::wxDataViewColumn( const wxString
&title
, wxDataViewCell
*cell
, size_t model_column
,
538 int fixed_width
, wxDataViewColumnSizing sizing
, int flags
) :
539 wxDataViewColumnBase( title
, cell
, model_column
, flags
)
543 m_width
= fixed_width
;
544 m_fixedWidth
= fixed_width
;
547 wxDataViewColumn::~wxDataViewColumn()
551 void wxDataViewColumn::SetTitle( const wxString
&title
)
553 wxDataViewColumnBase::SetTitle( title
);
557 int wxDataViewColumn::GetWidth()
562 void wxDataViewColumn::SetFixedWidth( int width
)
564 m_fixedWidth
= width
;
566 if (m_sizing
== wxDATAVIEW_COL_WIDTH_FIXED
)
573 int wxDataViewColumn::GetFixedWidth()
578 //-----------------------------------------------------------------------------
579 // wxDataViewHeaderWindow
580 //-----------------------------------------------------------------------------
582 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow
, wxWindow
)
584 BEGIN_EVENT_TABLE(wxDataViewHeaderWindow
,wxWindow
)
585 EVT_PAINT (wxDataViewHeaderWindow::OnPaint
)
586 EVT_MOUSE_EVENTS (wxDataViewHeaderWindow::OnMouse
)
587 EVT_SET_FOCUS (wxDataViewHeaderWindow::OnSetFocus
)
590 wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
591 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
592 wxWindow( parent
, id
, pos
, size
, 0, name
)
596 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
598 wxVisualAttributes attr
= wxPanel::GetClassDefaultAttributes();
599 SetOwnForegroundColour( attr
.colFg
);
600 SetOwnBackgroundColour( attr
.colBg
);
602 SetOwnFont( attr
.font
);
605 wxDataViewHeaderWindow::~wxDataViewHeaderWindow()
607 delete m_resizeCursor
;
610 void wxDataViewHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
613 GetClientSize( &w
, &h
);
615 wxPaintDC
dc( this );
618 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
621 m_owner
->GetViewStart( &x
, NULL
);
623 // account for the horz scrollbar offset
624 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
626 dc
.SetFont( GetFont() );
628 size_t cols
= GetOwner()->GetNumberOfColumns();
631 for (i
= 0; i
< cols
; i
++)
633 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
634 int width
= col
->GetWidth();
636 // the width of the rect to draw: make it smaller to fit entirely
637 // inside the column rect
646 wxRendererNative::Get().DrawHeaderButton
650 wxRect(xpos
+1, 1, cw
-1, ch
-1),
651 m_parent
->IsEnabled() ? 0
652 : (int)wxCONTROL_DISABLED
655 dc
.DrawText( col
->GetTitle(), xpos
+3, 3 );
661 void wxDataViewHeaderWindow::OnMouse( wxMouseEvent
&WXUNUSED(event
) )
665 void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent
&event
)
667 GetParent()->SetFocus();
671 //-----------------------------------------------------------------------------
672 // wxDataViewRenameTimer
673 //-----------------------------------------------------------------------------
675 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow
*owner
)
680 void wxDataViewRenameTimer::Notify()
682 m_owner
->OnRenameTimer();
685 //-----------------------------------------------------------------------------
686 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
687 //-----------------------------------------------------------------------------
689 BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper
, wxEvtHandler
)
690 EVT_CHAR (wxDataViewTextCtrlWrapper::OnChar
)
691 EVT_KEY_UP (wxDataViewTextCtrlWrapper::OnKeyUp
)
692 EVT_KILL_FOCUS (wxDataViewTextCtrlWrapper::OnKillFocus
)
695 wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper(
696 wxDataViewMainWindow
*owner
,
698 wxDataViewListModel
*model
,
699 size_t col
, size_t row
,
709 m_aboutToFinish
= false;
712 model
->GetValue( value
, col
, row
);
713 m_startValue
= value
.GetString();
715 m_owner
->GetOwner()->CalcScrolledPosition(
716 rectLabel
.x
, rectLabel
.y
, &rectLabel
.x
, &rectLabel
.y
);
718 m_text
->Create( owner
, wxID_ANY
, m_startValue
,
719 wxPoint(rectLabel
.x
-2,rectLabel
.y
-2),
720 wxSize(rectLabel
.width
+7,rectLabel
.height
+4) );
723 m_text
->PushEventHandler(this);
726 void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish()
728 m_aboutToFinish
= true;
730 // Notify the owner about the changes
733 // Even if vetoed, close the control (consistent with MSW)
737 void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent
&event
)
739 switch ( event
.m_keyCode
)
742 AcceptChangesAndFinish();
746 // m_owner->OnRenameCancelled( m_itemEdited );
755 void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent
&event
)
763 // auto-grow the textctrl
764 wxSize parentSize
= m_owner
->GetSize();
765 wxPoint myPos
= m_text
->GetPosition();
766 wxSize mySize
= m_text
->GetSize();
768 m_text
->GetTextExtent(m_text
->GetValue() + _T("MM"), &sx
, &sy
);
769 if (myPos
.x
+ sx
> parentSize
.x
)
770 sx
= parentSize
.x
- myPos
.x
;
773 m_text
->SetSize(sx
, wxDefaultCoord
);
778 void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent
&event
)
780 if ( !m_finished
&& !m_aboutToFinish
)
783 //if ( !AcceptChanges() )
784 // m_owner->OnRenameCancelled( m_itemEdited );
789 // We must let the native text control handle focus
793 bool wxDataViewTextCtrlWrapper::AcceptChanges()
795 const wxString value
= m_text
->GetValue();
797 if ( value
== m_startValue
)
798 // nothing changed, always accept
801 // if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
802 // vetoed by the user
805 // accepted, do rename the item
808 m_model
->SetValue( variant
, m_col
, m_row
);
809 m_model
->ValueChanged( m_col
, m_row
);
814 void wxDataViewTextCtrlWrapper::Finish()
820 m_text
->RemoveEventHandler(this);
821 m_owner
->FinishEditing(m_text
);
824 wxPendingDelete
.Append( this );
828 //-----------------------------------------------------------------------------
829 // wxDataViewMainWindow
830 //-----------------------------------------------------------------------------
832 int LINKAGEMODE
wxDataViewSelectionCmp( size_t row1
, size_t row2
)
834 if (row1
> row2
) return 1;
835 if (row1
== row2
) return 0;
840 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
)
842 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
)
843 EVT_PAINT (wxDataViewMainWindow::OnPaint
)
844 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse
)
845 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus
)
846 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus
)
847 EVT_CHAR (wxDataViewMainWindow::OnChar
)
850 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
851 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
852 wxWindow( parent
, id
, pos
, size
, 0, name
),
853 m_selection( wxDataViewSelectionCmp
)
858 m_lastOnSame
= false;
859 m_renameTimer
= new wxDataViewRenameTimer( this );
860 m_textctrlWrapper
= NULL
;
862 // TODO: user better initial values/nothing selected
866 // TODO: we need to calculate this smartly
869 m_highlightBrush
= new wxBrush
871 wxSystemSettings::GetColour
873 wxSYS_COLOUR_HIGHLIGHT
878 m_highlightUnfocusedBrush
= new wxBrush
880 wxSystemSettings::GetColour
882 wxSYS_COLOUR_BTNSHADOW
892 wxDataViewMainWindow::~wxDataViewMainWindow()
894 delete m_renameTimer
;
895 delete m_highlightBrush
;
896 delete m_highlightUnfocusedBrush
;
899 void wxDataViewMainWindow::OnRenameTimer()
901 // We have to call this here because changes may just have
902 // been made and no screen update taken place.
908 size_t cols
= GetOwner()->GetNumberOfColumns();
910 for (i
= 0; i
< cols
; i
++)
912 wxDataViewColumn
*c
= GetOwner()->GetColumn( i
);
913 if (c
== m_currentCol
)
915 xpos
+= c
->GetWidth();
917 wxRect
labelRect( xpos
, m_currentRow
* m_lineHeight
, m_currentCol
->GetWidth(), m_lineHeight
);
919 wxClassInfo
*textControlClass
= CLASSINFO(wxTextCtrl
);
921 wxTextCtrl
* const text
= (wxTextCtrl
*)textControlClass
->CreateObject();
922 m_textctrlWrapper
= new wxDataViewTextCtrlWrapper(this, text
, GetOwner()->GetModel(),
923 m_currentCol
->GetModelColumn(), m_currentRow
, labelRect
);
926 void wxDataViewMainWindow::FinishEditing( wxTextCtrl
*text
)
929 m_textctrlWrapper
= NULL
;
931 // SetFocusIgnoringChildren();
934 bool wxDataViewMainWindow::RowAppended()
939 bool wxDataViewMainWindow::RowPrepended()
944 bool wxDataViewMainWindow::RowInserted( size_t WXUNUSED(before
) )
949 bool wxDataViewMainWindow::RowDeleted( size_t WXUNUSED(row
) )
954 bool wxDataViewMainWindow::RowChanged( size_t WXUNUSED(row
) )
959 bool wxDataViewMainWindow::ValueChanged( size_t WXUNUSED(col
), size_t row
)
961 wxRect
rect( 0, row
*m_lineHeight
, 10000, m_lineHeight
);
962 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
963 Refresh( true, &rect
);
968 bool wxDataViewMainWindow::RowsReordered( size_t *WXUNUSED(new_order
) )
975 bool wxDataViewMainWindow::Cleared()
980 void wxDataViewMainWindow::UpdateDisplay()
985 void wxDataViewMainWindow::OnInternalIdle()
987 wxWindow::OnInternalIdle();
991 RecalculateDisplay();
996 void wxDataViewMainWindow::RecalculateDisplay()
998 wxDataViewListModel
*model
= GetOwner()->GetModel();
1006 size_t cols
= GetOwner()->GetNumberOfColumns();
1008 for (i
= 0; i
< cols
; i
++)
1010 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
1011 width
+= col
->GetWidth();
1014 int height
= model
->GetNumberOfRows() * m_lineHeight
;
1016 SetVirtualSize( width
, height
);
1017 GetOwner()->SetScrollRate( 10, m_lineHeight
);
1022 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
1024 wxWindow::ScrollWindow( dx
, dy
, rect
);
1025 GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 );
1028 void wxDataViewMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1030 wxPaintDC
dc( this );
1032 GetOwner()->PrepareDC( dc
);
1034 dc
.SetFont( GetFont() );
1036 wxRect update
= GetUpdateRegion().GetBox();
1037 m_owner
->CalcUnscrolledPosition( update
.x
, update
.y
, &update
.x
, &update
.y
);
1039 wxDataViewListModel
*model
= GetOwner()->GetModel();
1041 size_t item_start
= wxMax( 0, (update
.y
/ m_lineHeight
) );
1042 size_t item_count
= wxMin( (int)(((update
.y
+ update
.height
) / m_lineHeight
) - item_start
+ 1),
1043 (int)(model
->GetNumberOfRows()-item_start
) );
1047 dc
.SetBrush( *m_highlightBrush
);
1049 dc
.SetBrush( *m_highlightUnfocusedBrush
);
1050 dc
.SetPen( *wxTRANSPARENT_PEN
);
1053 for (item
= item_start
; item
< item_start
+item_count
; item
++)
1055 if (m_selection
.Index( item
) != wxNOT_FOUND
)
1057 wxRect
rect( 0, item
*m_lineHeight
+1, 10000, m_lineHeight
-2 );
1058 dc
.DrawRectangle( rect
);
1062 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1063 dc
.SetPen( *wxBLACK_PEN
);
1064 if (HasCurrentRow())
1066 wxRect
rect( 0, m_currentRow
*m_lineHeight
+1, 10000, m_lineHeight
-2 );
1067 dc
.DrawRectangle( rect
);
1072 cell_rect
.height
= m_lineHeight
;
1073 size_t cols
= GetOwner()->GetNumberOfColumns();
1075 for (i
= 0; i
< cols
; i
++)
1077 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
1078 wxDataViewCell
*cell
= col
->GetCell();
1079 cell_rect
.width
= col
->GetWidth();
1081 for (item
= item_start
; item
< item_start
+item_count
; item
++)
1083 cell_rect
.y
= item
*m_lineHeight
;
1085 model
->GetValue( value
, col
->GetModelColumn(), item
);
1086 cell
->SetValue( value
);
1087 wxSize size
= cell
->GetSize();
1088 // cannot be bigger than allocated space
1089 size
.x
= wxMin( size
.x
, cell_rect
.width
);
1090 size
.y
= wxMin( size
.y
, cell_rect
.height
);
1091 // TODO: check for left/right/centre alignment here
1094 item_rect
.x
= cell_rect
.x
+ (cell_rect
.width
/ 2) - (size
.x
/ 2);
1095 item_rect
.y
= cell_rect
.y
+ (cell_rect
.height
/ 2) - (size
.y
/ 2);
1097 item_rect
.width
= size
.x
;
1098 item_rect
.height
= size
.y
;
1099 cell
->Render( item_rect
, &dc
, 0 );
1102 cell_rect
.x
+= cell_rect
.width
;
1106 int wxDataViewMainWindow::GetCountPerPage()
1108 wxSize size
= GetClientSize();
1109 return size
.y
/ m_lineHeight
;
1112 int wxDataViewMainWindow::GetRowCount()
1114 return GetOwner()->GetModel()->GetNumberOfRows();
1117 void wxDataViewMainWindow::SelectAllRows( bool on
)
1119 m_selection
.Clear();
1123 for (i
= 0; i
< m_selection
.GetCount(); i
++)
1124 m_selection
.Add( i
);
1129 void wxDataViewMainWindow::SelectRow( size_t row
, bool on
)
1131 if (m_selection
.Index( row
) == wxNOT_FOUND
)
1135 m_selection
.Add( row
);
1143 m_selection
.Remove( row
);
1149 void wxDataViewMainWindow::SelectRows( size_t from
, size_t to
, bool on
)
1159 for (i
= from
; i
<= to
; i
++)
1161 if (m_selection
.Index( i
) == wxNOT_FOUND
)
1164 m_selection
.Add( i
);
1169 m_selection
.Remove( i
);
1172 RefreshRows( from
, to
);
1175 void wxDataViewMainWindow::ReverseRowSelection( size_t row
)
1177 if (m_selection
.Index( row
) == wxNOT_FOUND
)
1178 m_selection
.Add( row
);
1180 m_selection
.Remove( row
);
1184 bool wxDataViewMainWindow::IsRowSelected( size_t row
)
1186 return (m_selection
.Index( row
) != wxNOT_FOUND
);
1189 void wxDataViewMainWindow::RefreshRow( size_t row
)
1191 wxRect
rect( 0, row
*m_lineHeight
, 10000, m_lineHeight
);
1192 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
1194 wxSize client_size
= GetClientSize();
1195 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
1196 wxRect intersect_rect
= client_rect
.Intersect( rect
);
1197 if (intersect_rect
.width
> 0)
1198 Refresh( true, &intersect_rect
);
1201 void wxDataViewMainWindow::RefreshRows( size_t from
, size_t to
)
1210 wxRect
rect( 0, from
*m_lineHeight
, 10000, (to
-from
+1) * m_lineHeight
);
1211 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
1213 wxSize client_size
= GetClientSize();
1214 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
1215 wxRect intersect_rect
= client_rect
.Intersect( rect
);
1216 if (intersect_rect
.width
> 0)
1217 Refresh( true, &intersect_rect
);
1220 void wxDataViewMainWindow::RefreshRowsAfter( size_t firstRow
)
1222 size_t count
= GetRowCount();
1223 if (firstRow
> count
) return;
1225 wxRect
rect( 0, firstRow
*m_lineHeight
, 10000, count
* m_lineHeight
);
1226 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
1228 wxSize client_size
= GetClientSize();
1229 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
1230 wxRect intersect_rect
= client_rect
.Intersect( rect
);
1231 if (intersect_rect
.width
> 0)
1232 Refresh( true, &intersect_rect
);
1235 void wxDataViewMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
1237 wxCHECK_RET( newCurrent
< (size_t)GetRowCount(),
1238 _T("invalid item index in OnArrowChar()") );
1240 // if there is no selection, we cannot move it anywhere
1241 if (!HasCurrentRow())
1244 size_t oldCurrent
= m_currentRow
;
1246 // in single selection we just ignore Shift as we can't select several
1248 if ( event
.ShiftDown() /* && !IsSingleSel() */ )
1250 RefreshRow( oldCurrent
);
1252 m_currentRow
= newCurrent
;
1254 // select all the items between the old and the new one
1255 if ( oldCurrent
> newCurrent
)
1257 newCurrent
= oldCurrent
;
1258 oldCurrent
= m_currentRow
;
1261 SelectRows( oldCurrent
, newCurrent
, true );
1265 Refresh( oldCurrent
);
1267 // all previously selected items are unselected unless ctrl is held
1268 if ( !event
.ControlDown() )
1269 SelectAllRows(false);
1271 m_currentRow
= newCurrent
;
1273 if ( !event
.ControlDown() )
1274 SelectRow( m_currentRow
, true );
1280 void wxDataViewMainWindow::OnChar( wxKeyEvent
&event
)
1282 if (event
.GetKeyCode() == WXK_TAB
)
1284 wxNavigationKeyEvent nevent
;
1285 nevent
.SetWindowChange( event
.ControlDown() );
1286 nevent
.SetDirection( !event
.ShiftDown() );
1287 nevent
.SetEventObject( GetParent()->GetParent() );
1288 nevent
.SetCurrentFocus( m_parent
);
1289 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
))
1293 // no item -> nothing to do
1294 if (!HasCurrentRow())
1300 // don't use m_linesPerPage directly as it might not be computed yet
1301 const int pageSize
= GetCountPerPage();
1302 wxCHECK_RET( pageSize
, _T("should have non zero page size") );
1304 switch ( event
.GetKeyCode() )
1307 if ( m_currentRow
> 0 )
1308 OnArrowChar( m_currentRow
- 1, event
);
1312 if ( m_currentRow
< (size_t)GetRowCount() - 1 )
1313 OnArrowChar( m_currentRow
+ 1, event
);
1318 OnArrowChar( GetRowCount() - 1, event
);
1323 OnArrowChar( 0, event
);
1328 int steps
= pageSize
- 1;
1329 int index
= m_currentRow
- steps
;
1333 OnArrowChar( index
, event
);
1339 int steps
= pageSize
- 1;
1340 size_t index
= m_currentRow
+ steps
;
1341 size_t count
= GetRowCount();
1342 if ( index
>= count
)
1345 OnArrowChar( index
, event
);
1354 void wxDataViewMainWindow::OnMouse( wxMouseEvent
&event
)
1356 int x
= event
.GetX();
1357 int y
= event
.GetY();
1358 m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y
);
1360 wxDataViewColumn
*col
= NULL
;
1363 size_t cols
= GetOwner()->GetNumberOfColumns();
1365 for (i
= 0; i
< cols
; i
++)
1367 wxDataViewColumn
*c
= GetOwner()->GetColumn( i
);
1368 if (x
< xpos
+ c
->GetWidth())
1373 xpos
+= c
->GetWidth();
1377 wxDataViewCell
*cell
= col
->GetCell();
1379 size_t row
= y
/ m_lineHeight
;
1381 wxDataViewListModel
*model
= GetOwner()->GetModel();
1383 if (event
.ButtonDClick())
1385 m_renameTimer
->Stop();
1386 m_lastOnSame
= false;
1389 if (event
.LeftDClick())
1391 if (cell
->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE
)
1394 model
->GetValue( value
, col
->GetModelColumn(), row
);
1395 cell
->SetValue( value
);
1396 wxRect
cell_rect( xpos
, row
* m_lineHeight
, col
->GetWidth(), m_lineHeight
);
1397 cell
->Activate( cell_rect
, model
, col
->GetModelColumn(), row
);
1406 if ((col
== m_currentCol
) & (row
== m_currentRow
) &&
1407 (cell
->GetMode() == wxDATAVIEW_CELL_EDITABLE
) )
1409 m_renameTimer
->Start( 100, true );
1413 m_lastOnSame
= false;
1415 if (event
.LeftDown())
1417 wxDataViewColumn
*oldCurrentCol
= m_currentCol
;
1418 size_t oldCurrentRow
= m_currentRow
;
1420 // Update selection here...
1423 RefreshRow( oldCurrentRow
);
1424 RefreshRow( m_currentRow
);
1426 m_lastOnSame
= (col
== oldCurrentCol
) && (row
== oldCurrentRow
);
1434 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent
&event
)
1438 if (HasCurrentRow())
1444 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent
&event
)
1448 if (HasCurrentRow())
1454 //-----------------------------------------------------------------------------
1456 //-----------------------------------------------------------------------------
1458 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
)
1460 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
)
1461 EVT_SIZE(wxDataViewCtrl::OnSize
)
1464 wxDataViewCtrl::~wxDataViewCtrl()
1467 GetModel()->RemoveNotifier( m_notifier
);
1470 void wxDataViewCtrl::Init()
1475 bool wxDataViewCtrl::Create(wxWindow
*parent
, wxWindowID id
,
1476 const wxPoint
& pos
, const wxSize
& size
,
1477 long style
, const wxValidator
& validator
)
1479 if (!wxControl::Create( parent
, id
, pos
, size
, style
| wxScrolledWindowStyle
|wxSUNKEN_BORDER
, validator
))
1485 MacSetClipChildren( true ) ;
1488 m_clientArea
= new wxDataViewMainWindow( this, wxID_ANY
);
1489 m_headerArea
= new wxDataViewHeaderWindow( this, wxID_ANY
, wxDefaultPosition
, wxSize(wxDefaultCoord
,25) );
1491 SetTargetWindow( m_clientArea
);
1493 wxBoxSizer
*sizer
= new wxBoxSizer( wxVERTICAL
);
1494 sizer
->Add( m_headerArea
, 0, wxGROW
);
1495 sizer
->Add( m_clientArea
, 1, wxGROW
);
1502 WXLRESULT
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
,
1506 WXLRESULT rc
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
);
1509 // we need to process arrows ourselves for scrolling
1510 if ( nMsg
== WM_GETDLGCODE
)
1512 rc
|= DLGC_WANTARROWS
;
1520 void wxDataViewCtrl::OnSize( wxSizeEvent
&WXUNUSED(event
) )
1522 // We need to override OnSize so that our scrolled
1523 // window a) does call Layout() to use sizers for
1524 // positioning the controls but b) does not query
1525 // the sizer for their size and use that for setting
1526 // the scrollable area as set that ourselves by
1527 // calling SetScrollbar() further down.
1534 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel
*model
)
1536 if (!wxDataViewCtrlBase::AssociateModel( model
))
1539 m_notifier
= new wxGenericDataViewListModelNotifier( m_clientArea
);
1541 model
->AddNotifier( m_notifier
);
1543 m_clientArea
->UpdateDisplay();
1548 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn
*col
)
1550 if (!wxDataViewCtrlBase::AppendColumn(col
))
1553 m_clientArea
->UpdateDisplay();
1559 // !wxUSE_GENERICDATAVIEWCTRL
1562 // wxUSE_DATAVIEWCTRL