1 /////////////////////////////////////////////////////////////////////////////
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"
15 #if wxUSE_DATAVIEWCTRL
17 #include "wx/dataview.h"
19 #ifdef wxUSE_GENERICDATAVIEWCTRL
21 #include "wx/stockitem.h"
22 #include "wx/dcclient.h"
23 #include "wx/calctrl.h"
24 #include "wx/popupwin.h"
27 #include "wx/renderer.h"
30 #include <windows.h> // for DLGC_WANTARROWS
31 #include "wx/msw/winundef.h"
34 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
40 // ---------------------------------------------------------
41 // wxGenericDataViewListModelNotifier
42 // ---------------------------------------------------------
44 class wxGenericDataViewListModelNotifier
: public wxDataViewListModelNotifier
47 wxGenericDataViewListModelNotifier( wxDataViewListModel
*wx_model
);
49 virtual bool RowAppended();
50 virtual bool RowPrepended();
51 virtual bool RowInserted( size_t before
);
52 virtual bool RowDeleted( size_t row
);
53 virtual bool RowChanged( size_t row
);
54 virtual bool ValueChanged( size_t col
, size_t row
);
55 virtual bool RowsReordered( size_t *new_order
);
56 virtual bool Cleared();
58 wxDataViewListModel
*m_wx_model
;
61 // ---------------------------------------------------------
62 // wxGenericDataViewListModelNotifier
63 // ---------------------------------------------------------
65 wxGenericDataViewListModelNotifier
::wxGenericDataViewListModelNotifier(
66 wxDataViewListModel
*wx_model
)
68 m_wx_model
= wx_model
;
71 bool wxGenericDataViewListModelNotifier
::RowAppended()
73 size_t pos
= m_wx_model
->GetNumberOfRows()-1;
78 bool wxGenericDataViewListModelNotifier
::RowPrepended()
83 bool wxGenericDataViewListModelNotifier
::RowInserted( size_t before
)
88 bool wxGenericDataViewListModelNotifier
::RowDeleted( size_t row
)
93 bool wxGenericDataViewListModelNotifier
::RowChanged( size_t row
)
98 bool wxGenericDataViewListModelNotifier
::ValueChanged( size_t model_col
, size_t model_row
)
100 wxNode
*node
= GetOwner()->m_viewingColumns
.GetFirst();
103 wxDataViewViewingColumn
* viewing_column
= (wxDataViewViewingColumn
*) node
->GetData();
104 if (viewing_column
->m_modelColumn
== model_col
)
109 node
= node
->GetNext();
115 bool wxGenericDataViewListModelNotifier
::RowsReordered( size_t *new_order
)
117 wxNode
*node
= GetOwner()->m_viewingColumns
.GetFirst();
120 wxDataViewViewingColumn
* viewing_column
= (wxDataViewViewingColumn
*) node
->GetData();
122 node
= node
->GetNext();
128 bool wxGenericDataViewListModelNotifier
::Cleared()
133 // ---------------------------------------------------------
135 // ---------------------------------------------------------
137 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCell
, wxDataViewCellBase
)
139 wxDataViewCell
::wxDataViewCell( const wxString
&varianttype
, wxDataViewCellMode mode
) :
140 wxDataViewCellBase( varianttype
, mode
)
145 wxDataViewCell
::~wxDataViewCell()
151 wxDC
*wxDataViewCell
::GetDC()
155 if (GetOwner() == NULL
)
157 if (GetOwner()->GetOwner() == NULL
)
159 m_dc
= new wxClientDC( GetOwner()->GetOwner() );
165 // ---------------------------------------------------------
166 // wxDataViewCustomCell
167 // ---------------------------------------------------------
169 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomCell
, wxDataViewCell
)
171 wxDataViewCustomCell
::wxDataViewCustomCell( const wxString
&varianttype
,
172 wxDataViewCellMode mode
) :
173 wxDataViewCell( varianttype
, mode
)
178 // ---------------------------------------------------------
179 // wxDataViewTextCell
180 // ---------------------------------------------------------
182 IMPLEMENT_ABSTRACT_CLASS(wxDataViewTextCell
, wxDataViewCustomCell
)
184 wxDataViewTextCell
::wxDataViewTextCell( const wxString
&varianttype
, wxDataViewCellMode mode
) :
185 wxDataViewCustomCell( varianttype
, mode
)
189 bool wxDataViewTextCell
::SetValue( const wxVariant
&value
)
194 bool wxDataViewTextCell
::GetValue( wxVariant
&value
)
199 bool wxDataViewTextCell
::Render( wxRect cell
, wxDC
*dc
, int state
)
204 wxSize wxDataViewTextCell
::GetSize()
206 return wxSize(80,20);
209 // ---------------------------------------------------------
210 // wxDataViewToggleCell
211 // ---------------------------------------------------------
213 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleCell
, wxDataViewCustomCell
)
215 wxDataViewToggleCell
::wxDataViewToggleCell( const wxString
&varianttype
,
216 wxDataViewCellMode mode
) :
217 wxDataViewCustomCell( varianttype
, mode
)
221 bool wxDataViewToggleCell
::SetValue( const wxVariant
&value
)
226 bool wxDataViewToggleCell
::GetValue( wxVariant
&value
)
231 bool wxDataViewToggleCell
::Render( wxRect cell
, wxDC
*dc
, int state
)
236 wxSize wxDataViewToggleCell
::GetSize()
238 return wxSize(20,20);
241 // ---------------------------------------------------------
242 // wxDataViewProgressCell
243 // ---------------------------------------------------------
245 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressCell
, wxDataViewCustomCell
)
247 wxDataViewProgressCell
::wxDataViewProgressCell( const wxString
&label
,
248 const wxString
&varianttype
, wxDataViewCellMode mode
) :
249 wxDataViewCustomCell( varianttype
, mode
)
255 wxDataViewProgressCell
::~wxDataViewProgressCell()
259 bool wxDataViewProgressCell
::SetValue( const wxVariant
&value
)
261 m_value
= (long) value
;
263 if (m_value
< 0) m_value
= 0;
264 if (m_value
> 100) m_value
= 100;
269 bool wxDataViewProgressCell
::Render( wxRect cell
, wxDC
*dc
, int state
)
271 double pct
= (double)m_value
/ 100.0;
273 bar
.width
= (int)(cell
.width
* pct
);
274 dc
->SetPen( *wxTRANSPARENT_PEN
);
275 dc
->SetBrush( *wxBLUE_BRUSH
);
276 dc
->DrawRectangle( bar
);
278 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
279 dc
->SetPen( *wxBLACK_PEN
);
280 dc
->DrawRectangle( cell
);
285 wxSize wxDataViewProgressCell
::GetSize()
287 return wxSize(40,12);
290 // ---------------------------------------------------------
291 // wxDataViewDateCell
292 // ---------------------------------------------------------
294 class wxDataViewDateCellPopupTransient
: public wxPopupTransientWindow
297 wxDataViewDateCellPopupTransient( wxWindow
* parent
, wxDateTime
*value
,
298 wxDataViewListModel
*model
, size_t col
, size_t row
) :
299 wxPopupTransientWindow( parent
, wxBORDER_SIMPLE
)
304 m_cal
= new wxCalendarCtrl( this, -1, *value
);
305 wxBoxSizer
*sizer
= new wxBoxSizer( wxHORIZONTAL
);
306 sizer
->Add( m_cal
, 1, wxGROW
);
311 virtual void OnDismiss()
315 void OnCalendar( wxCalendarEvent
&event
);
317 wxCalendarCtrl
*m_cal
;
318 wxDataViewListModel
*m_model
;
323 DECLARE_EVENT_TABLE()
326 BEGIN_EVENT_TABLE(wxDataViewDateCellPopupTransient
,wxPopupTransientWindow
)
327 EVT_CALENDAR( -1, wxDataViewDateCellPopupTransient
::OnCalendar
)
330 void wxDataViewDateCellPopupTransient
::OnCalendar( wxCalendarEvent
&event
)
332 wxDateTime date
= event
.GetDate();
333 wxVariant value
= date
;
334 m_model
->SetValue( value
, m_col
, m_row
);
335 m_model
->ValueChanged( m_col
, m_row
);
339 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateCell
, wxDataViewCustomCell
)
341 wxDataViewDateCell
::wxDataViewDateCell( const wxString
&varianttype
,
342 wxDataViewCellMode mode
) :
343 wxDataViewCustomCell( varianttype
, mode
)
347 bool wxDataViewDateCell
::SetValue( const wxVariant
&value
)
349 m_date
= value
.GetDateTime();
354 bool wxDataViewDateCell
::Render( wxRect cell
, wxDC
*dc
, int state
)
356 dc
->SetFont( GetOwner()->GetOwner()->GetFont() );
357 wxString tmp
= m_date
.FormatDate();
358 dc
->DrawText( tmp
, cell
.x
, cell
.y
);
363 wxSize wxDataViewDateCell
::GetSize()
365 wxDataViewCtrl
* view
= GetOwner()->GetOwner();
366 wxString tmp
= m_date
.FormatDate();
368 view
->GetTextExtent( tmp
, &x
, &y
, &d
);
369 return wxSize(x
,y
+d
);
372 bool wxDataViewDateCell
::Activate( wxRect cell
, wxDataViewListModel
*model
, size_t col
, size_t row
)
375 model
->GetValue( variant
, col
, row
);
376 wxDateTime value
= variant
.GetDateTime();
378 wxDataViewDateCellPopupTransient
*popup
= new wxDataViewDateCellPopupTransient(
379 GetOwner()->GetOwner()->GetParent(), &value
, model
, col
, row
);
380 wxPoint pos
= wxGetMousePosition();
383 popup
->Popup( popup
->m_cal
);
388 // ---------------------------------------------------------
390 // ---------------------------------------------------------
392 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn
, wxDataViewColumnBase
)
394 wxDataViewColumn
::wxDataViewColumn( const wxString
&title
, wxDataViewCell
*cell
,
395 size_t model_column
, int flags
) :
396 wxDataViewColumnBase( title
, cell
, model_column
, flags
)
401 wxDataViewColumn
::~wxDataViewColumn()
405 void wxDataViewColumn
::SetTitle( const wxString
&title
)
407 wxDataViewColumnBase
::SetTitle( title
);
411 //-----------------------------------------------------------------------------
412 // wxDataViewHeaderWindow
413 //-----------------------------------------------------------------------------
415 class wxDataViewHeaderWindow
: public wxWindow
418 wxDataViewHeaderWindow( wxDataViewCtrl
*parent
,
420 const wxPoint
&pos
= wxDefaultPosition
,
421 const wxSize
&size
= wxDefaultSize
,
422 const wxString
&name
= wxT("wxdataviewctrlheaderwindow") );
423 ~wxDataViewHeaderWindow();
425 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
426 wxDataViewCtrl
*GetOwner() { return m_owner
; }
428 void OnPaint( wxPaintEvent
&event
);
429 void OnMouse( wxMouseEvent
&event
);
430 void OnSetFocus( wxFocusEvent
&event
);
433 wxDataViewCtrl
*m_owner
;
434 wxCursor
*m_resizeCursor
;
437 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow
)
438 DECLARE_EVENT_TABLE()
441 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow
, wxWindow
)
443 BEGIN_EVENT_TABLE(wxDataViewHeaderWindow
,wxWindow
)
444 EVT_PAINT (wxDataViewHeaderWindow
::OnPaint
)
445 EVT_MOUSE_EVENTS (wxDataViewHeaderWindow
::OnMouse
)
446 EVT_SET_FOCUS (wxDataViewHeaderWindow
::OnSetFocus
)
449 wxDataViewHeaderWindow
::wxDataViewHeaderWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
450 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
451 wxWindow( parent
, id
, pos
, size
, 0, name
)
455 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
457 wxVisualAttributes attr
= wxPanel
::GetClassDefaultAttributes();
458 SetOwnForegroundColour( attr
.colFg
);
459 SetOwnBackgroundColour( attr
.colBg
);
461 SetOwnFont( attr
.font
);
464 wxDataViewHeaderWindow
::~wxDataViewHeaderWindow()
466 delete m_resizeCursor
;
469 void wxDataViewHeaderWindow
::OnPaint( wxPaintEvent
&event
)
472 GetClientSize( &w
, &h
);
474 wxPaintDC
dc( this );
477 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
480 m_owner
->GetViewStart( &x
, NULL
);
482 // account for the horz scrollbar offset
483 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
485 dc
.SetFont( GetFont() );
487 size_t cols
= GetOwner()->GetNumberOfColumns();
490 for (i
= 0; i
< cols
; i
++)
492 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
493 int width
= col
->GetWidth();
495 // the width of the rect to draw: make it smaller to fit entirely
496 // inside the column rect
505 wxRendererNative
::Get().DrawHeaderButton
509 wxRect(xpos
, 0, cw
, ch
),
510 m_parent
->IsEnabled() ?
0
511 : (int)wxCONTROL_DISABLED
514 dc
.DrawText( col
->GetTitle(), xpos
+3, 3 );
520 void wxDataViewHeaderWindow
::OnMouse( wxMouseEvent
&event
)
524 void wxDataViewHeaderWindow
::OnSetFocus( wxFocusEvent
&event
)
529 //-----------------------------------------------------------------------------
530 // wxDataViewMainWindow
531 //-----------------------------------------------------------------------------
533 class wxDataViewMainWindow
: public wxWindow
536 wxDataViewMainWindow( wxDataViewCtrl
*parent
,
538 const wxPoint
&pos
= wxDefaultPosition
,
539 const wxSize
&size
= wxDefaultSize
,
540 const wxString
&name
= wxT("wxdataviewctrlmainwindow") );
541 ~wxDataViewMainWindow();
543 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
544 wxDataViewCtrl
*GetOwner() { return m_owner
; }
546 void OnPaint( wxPaintEvent
&event
);
547 void OnMouse( wxMouseEvent
&event
);
548 void OnSetFocus( wxFocusEvent
&event
);
550 void UpdateDisplay();
551 void RecalculateDisplay();
552 void OnInternalIdle();
554 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
);
556 wxDataViewCtrl
*m_owner
;
561 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
)
562 DECLARE_EVENT_TABLE()
565 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
)
567 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
)
568 EVT_PAINT (wxDataViewMainWindow
::OnPaint
)
569 EVT_MOUSE_EVENTS (wxDataViewMainWindow
::OnMouse
)
570 EVT_SET_FOCUS (wxDataViewMainWindow
::OnSetFocus
)
573 wxDataViewMainWindow
::wxDataViewMainWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
574 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
575 wxWindow( parent
, id
, pos
, size
, 0, name
)
579 // We need to calculate this smartly..
585 wxDataViewMainWindow
::~wxDataViewMainWindow()
589 void wxDataViewMainWindow
::UpdateDisplay()
594 void wxDataViewMainWindow
::OnInternalIdle()
596 wxWindow
::OnInternalIdle();
600 RecalculateDisplay();
605 void wxDataViewMainWindow
::RecalculateDisplay()
607 wxDataViewListModel
*model
= GetOwner()->GetModel();
615 size_t cols
= GetOwner()->GetNumberOfColumns();
617 for (i
= 0; i
< cols
; i
++)
619 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
620 width
+= col
->GetWidth();
623 int height
= model
->GetNumberOfRows() * m_lineHeight
;
625 SetVirtualSize( width
, height
);
626 GetOwner()->SetScrollRate( 10, m_lineHeight
);
631 void wxDataViewMainWindow
::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
633 wxWindow
::ScrollWindow( dx
, dy
, rect
);
634 GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 );
637 void wxDataViewMainWindow
::OnPaint( wxPaintEvent
&event
)
639 wxPaintDC
dc( this );
641 GetOwner()->PrepareDC( dc
);
643 dc
.SetFont( GetFont() );
645 dc
.DrawText( wxT("main window"), 5, 5 );
648 void wxDataViewMainWindow
::OnMouse( wxMouseEvent
&event
)
653 void wxDataViewMainWindow
::OnSetFocus( wxFocusEvent
&event
)
658 //-----------------------------------------------------------------------------
660 //-----------------------------------------------------------------------------
662 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
)
664 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
)
665 EVT_SIZE(wxDataViewCtrl
::OnSize
)
668 wxDataViewCtrl
::~wxDataViewCtrl()
671 GetModel()->RemoveNotifier( m_notifier
);
674 void wxDataViewCtrl
::Init()
679 bool wxDataViewCtrl
::Create(wxWindow
*parent
, wxWindowID id
,
680 const wxPoint
& pos
, const wxSize
& size
,
681 long style
, const wxValidator
& validator
)
683 if (!wxControl
::Create( parent
, id
, pos
, size
, style
| wxScrolledWindowStyle
|wxSUNKEN_BORDER
, validator
))
689 MacSetClipChildren( true ) ;
692 m_clientArea
= new wxDataViewMainWindow( this, -1 );
693 m_headerArea
= new wxDataViewHeaderWindow( this, -1, wxDefaultPosition
, wxSize(-1,25) );
695 SetTargetWindow( m_clientArea
);
697 wxBoxSizer
*sizer
= new wxBoxSizer( wxVERTICAL
);
698 sizer
->Add( m_headerArea
, 0, wxGROW
);
699 sizer
->Add( m_clientArea
, 1, wxGROW
);
706 WXLRESULT wxDataViewCtrl
::MSWWindowProc(WXUINT nMsg
,
710 WXLRESULT rc
= wxPanel
::MSWWindowProc(nMsg
, wParam
, lParam
);
713 // we need to process arrows ourselves for scrolling
714 if ( nMsg
== WM_GETDLGCODE
)
716 rc
|= DLGC_WANTARROWS
;
724 void wxDataViewCtrl
::OnSize( wxSizeEvent
&event
)
726 // We need to override OnSize so that our scrolled
727 // window a) does call Layout() to use sizers for
728 // positioning the controls but b) does not query
729 // the sizer for their size and use that for setting
730 // the scrollable area as set that ourselves by
731 // calling SetScrollbar() further down.
738 bool wxDataViewCtrl
::AssociateModel( wxDataViewListModel
*model
)
740 if (!wxDataViewCtrlBase
::AssociateModel( model
))
743 m_notifier
= new wxGenericDataViewListModelNotifier( model
);
745 model
->AddNotifier( m_notifier
);
747 m_clientArea
->UpdateDisplay();
752 bool wxDataViewCtrl
::AppendColumn( wxDataViewColumn
*col
)
754 if (!wxDataViewCtrlBase
::AppendColumn(col
))
757 m_clientArea
->UpdateDisplay();
763 // !wxUSE_GENERICDATAVIEWCTRL
766 // wxUSE_DATAVIEWCTRL