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
)
144 // ---------------------------------------------------------
145 // wxDataViewTextCell
146 // ---------------------------------------------------------
148 IMPLEMENT_ABSTRACT_CLASS(wxDataViewTextCell
, wxDataViewCell
)
150 wxDataViewTextCell::wxDataViewTextCell( const wxString
&varianttype
, wxDataViewCellMode mode
) :
151 wxDataViewCell( varianttype
, mode
)
155 bool wxDataViewTextCell::SetValue( const wxVariant
&value
)
160 bool wxDataViewTextCell::GetValue( wxVariant
&value
)
165 // ---------------------------------------------------------
166 // wxDataViewToggleCell
167 // ---------------------------------------------------------
169 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleCell
, wxDataViewCell
)
171 wxDataViewToggleCell::wxDataViewToggleCell( const wxString
&varianttype
,
172 wxDataViewCellMode mode
) :
173 wxDataViewCell( varianttype
, mode
)
177 bool wxDataViewToggleCell::SetValue( const wxVariant
&value
)
182 bool wxDataViewToggleCell::GetValue( wxVariant
&value
)
187 // ---------------------------------------------------------
188 // wxDataViewCustomCell
189 // ---------------------------------------------------------
191 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomCell
, wxDataViewCell
)
193 wxDataViewCustomCell::wxDataViewCustomCell( const wxString
&varianttype
,
194 wxDataViewCellMode mode
) :
195 wxDataViewCell( varianttype
, mode
)
202 bool wxDataViewCustomCell::Init()
207 wxDataViewCustomCell::~wxDataViewCustomCell()
213 wxDC
*wxDataViewCustomCell::GetDC()
217 if (GetOwner() == NULL
)
219 if (GetOwner()->GetOwner() == NULL
)
221 m_dc
= new wxClientDC( GetOwner()->GetOwner() );
227 // ---------------------------------------------------------
228 // wxDataViewProgressCell
229 // ---------------------------------------------------------
231 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressCell
, wxDataViewCustomCell
)
233 wxDataViewProgressCell::wxDataViewProgressCell( const wxString
&label
,
234 const wxString
&varianttype
, wxDataViewCellMode mode
) :
235 wxDataViewCustomCell( varianttype
, mode
)
241 wxDataViewProgressCell::~wxDataViewProgressCell()
245 bool wxDataViewProgressCell::SetValue( const wxVariant
&value
)
247 m_value
= (long) value
;
249 if (m_value
< 0) m_value
= 0;
250 if (m_value
> 100) m_value
= 100;
255 bool wxDataViewProgressCell::Render( wxRect cell
, wxDC
*dc
, int state
)
257 double pct
= (double)m_value
/ 100.0;
259 bar
.width
= (int)(cell
.width
* pct
);
260 dc
->SetPen( *wxTRANSPARENT_PEN
);
261 dc
->SetBrush( *wxBLUE_BRUSH
);
262 dc
->DrawRectangle( bar
);
264 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
265 dc
->SetPen( *wxBLACK_PEN
);
266 dc
->DrawRectangle( cell
);
271 wxSize
wxDataViewProgressCell::GetSize()
273 return wxSize(40,12);
276 // ---------------------------------------------------------
277 // wxDataViewDateCell
278 // ---------------------------------------------------------
280 class wxDataViewDateCellPopupTransient
: public wxPopupTransientWindow
283 wxDataViewDateCellPopupTransient( wxWindow
* parent
, wxDateTime
*value
,
284 wxDataViewListModel
*model
, size_t col
, size_t row
) :
285 wxPopupTransientWindow( parent
, wxBORDER_SIMPLE
)
290 m_cal
= new wxCalendarCtrl( this, -1, *value
);
291 wxBoxSizer
*sizer
= new wxBoxSizer( wxHORIZONTAL
);
292 sizer
->Add( m_cal
, 1, wxGROW
);
297 virtual void OnDismiss()
301 void OnCalendar( wxCalendarEvent
&event
);
303 wxCalendarCtrl
*m_cal
;
304 wxDataViewListModel
*m_model
;
309 DECLARE_EVENT_TABLE()
312 BEGIN_EVENT_TABLE(wxDataViewDateCellPopupTransient
,wxPopupTransientWindow
)
313 EVT_CALENDAR( -1, wxDataViewDateCellPopupTransient::OnCalendar
)
316 void wxDataViewDateCellPopupTransient::OnCalendar( wxCalendarEvent
&event
)
318 wxDateTime date
= event
.GetDate();
319 wxVariant value
= date
;
320 m_model
->SetValue( value
, m_col
, m_row
);
321 m_model
->ValueChanged( m_col
, m_row
);
325 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateCell
, wxDataViewCustomCell
)
327 wxDataViewDateCell::wxDataViewDateCell( const wxString
&varianttype
,
328 wxDataViewCellMode mode
) :
329 wxDataViewCustomCell( varianttype
, mode
)
333 bool wxDataViewDateCell::SetValue( const wxVariant
&value
)
335 m_date
= value
.GetDateTime();
340 bool wxDataViewDateCell::Render( wxRect cell
, wxDC
*dc
, int state
)
342 dc
->SetFont( GetOwner()->GetOwner()->GetFont() );
343 wxString tmp
= m_date
.FormatDate();
344 dc
->DrawText( tmp
, cell
.x
, cell
.y
);
349 wxSize
wxDataViewDateCell::GetSize()
351 wxDataViewCtrl
* view
= GetOwner()->GetOwner();
352 wxString tmp
= m_date
.FormatDate();
354 view
->GetTextExtent( tmp
, &x
, &y
, &d
);
355 return wxSize(x
,y
+d
);
358 bool wxDataViewDateCell::Activate( wxRect cell
, wxDataViewListModel
*model
, size_t col
, size_t row
)
361 model
->GetValue( variant
, col
, row
);
362 wxDateTime value
= variant
.GetDateTime();
364 wxDataViewDateCellPopupTransient
*popup
= new wxDataViewDateCellPopupTransient(
365 GetOwner()->GetOwner()->GetParent(), &value
, model
, col
, row
);
366 wxPoint pos
= wxGetMousePosition();
369 popup
->Popup( popup
->m_cal
);
374 // ---------------------------------------------------------
376 // ---------------------------------------------------------
378 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn
, wxDataViewColumnBase
)
380 wxDataViewColumn::wxDataViewColumn( const wxString
&title
, wxDataViewCell
*cell
,
381 size_t model_column
, int flags
) :
382 wxDataViewColumnBase( title
, cell
, model_column
, flags
)
387 wxDataViewColumn::~wxDataViewColumn()
391 void wxDataViewColumn::SetTitle( const wxString
&title
)
393 wxDataViewColumnBase::SetTitle( title
);
397 //-----------------------------------------------------------------------------
398 // wxDataViewHeaderWindow
399 //-----------------------------------------------------------------------------
401 class wxDataViewHeaderWindow
: public wxWindow
404 wxDataViewHeaderWindow( wxDataViewCtrl
*parent
,
406 const wxPoint
&pos
= wxDefaultPosition
,
407 const wxSize
&size
= wxDefaultSize
,
408 const wxString
&name
= wxT("wxdataviewctrlheaderwindow") );
409 ~wxDataViewHeaderWindow();
411 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
412 wxDataViewCtrl
*GetOwner() { return m_owner
; }
414 void OnPaint( wxPaintEvent
&event
);
415 void OnMouse( wxMouseEvent
&event
);
416 void OnSetFocus( wxFocusEvent
&event
);
419 wxDataViewCtrl
*m_owner
;
420 wxCursor
*m_resizeCursor
;
423 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow
)
424 DECLARE_EVENT_TABLE()
427 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow
, wxWindow
)
429 BEGIN_EVENT_TABLE(wxDataViewHeaderWindow
,wxWindow
)
430 EVT_PAINT (wxDataViewHeaderWindow::OnPaint
)
431 EVT_MOUSE_EVENTS (wxDataViewHeaderWindow::OnMouse
)
432 EVT_SET_FOCUS (wxDataViewHeaderWindow::OnSetFocus
)
435 wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
436 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
437 wxWindow( parent
, id
, pos
, size
, 0, name
)
441 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
443 wxVisualAttributes attr
= wxPanel::GetClassDefaultAttributes();
444 SetOwnForegroundColour( attr
.colFg
);
445 SetOwnBackgroundColour( attr
.colBg
);
447 SetOwnFont( attr
.font
);
450 wxDataViewHeaderWindow::~wxDataViewHeaderWindow()
452 delete m_resizeCursor
;
455 void wxDataViewHeaderWindow::OnPaint( wxPaintEvent
&event
)
458 GetClientSize( &w
, &h
);
460 wxPaintDC
dc( this );
463 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
466 m_owner
->GetViewStart( &x
, NULL
);
468 // account for the horz scrollbar offset
469 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
471 dc
.SetFont( GetFont() );
473 size_t cols
= GetOwner()->GetNumberOfColumns();
476 for (i
= 0; i
< cols
; i
++)
478 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
479 int width
= col
->GetWidth();
481 // the width of the rect to draw: make it smaller to fit entirely
482 // inside the column rect
491 wxRendererNative::Get().DrawHeaderButton
495 wxRect(xpos
, 0, cw
, ch
),
496 m_parent
->IsEnabled() ? 0
497 : (int)wxCONTROL_DISABLED
500 dc
.DrawText( col
->GetTitle(), xpos
+3, 3 );
506 void wxDataViewHeaderWindow::OnMouse( wxMouseEvent
&event
)
510 void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent
&event
)
515 //-----------------------------------------------------------------------------
516 // wxDataViewMainWindow
517 //-----------------------------------------------------------------------------
519 class wxDataViewMainWindow
: public wxWindow
522 wxDataViewMainWindow( wxDataViewCtrl
*parent
,
524 const wxPoint
&pos
= wxDefaultPosition
,
525 const wxSize
&size
= wxDefaultSize
,
526 const wxString
&name
= wxT("wxdataviewctrlmainwindow") );
527 ~wxDataViewMainWindow();
529 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
530 wxDataViewCtrl
*GetOwner() { return m_owner
; }
532 void OnPaint( wxPaintEvent
&event
);
533 void OnMouse( wxMouseEvent
&event
);
534 void OnSetFocus( wxFocusEvent
&event
);
536 void UpdateDisplay();
537 void RecalculateDisplay();
538 void OnInternalIdle();
540 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
);
542 wxDataViewCtrl
*m_owner
;
547 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
)
548 DECLARE_EVENT_TABLE()
551 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
)
553 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
)
554 EVT_PAINT (wxDataViewMainWindow::OnPaint
)
555 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse
)
556 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus
)
559 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
560 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
561 wxWindow( parent
, id
, pos
, size
, 0, name
)
565 // We need to calculate this smartly..
571 wxDataViewMainWindow::~wxDataViewMainWindow()
575 void wxDataViewMainWindow::UpdateDisplay()
580 void wxDataViewMainWindow::OnInternalIdle()
582 wxWindow::OnInternalIdle();
586 RecalculateDisplay();
591 void wxDataViewMainWindow::RecalculateDisplay()
593 wxDataViewListModel
*model
= GetOwner()->GetModel();
601 size_t cols
= GetOwner()->GetNumberOfColumns();
603 for (i
= 0; i
< cols
; i
++)
605 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
606 width
+= col
->GetWidth();
609 int height
= model
->GetNumberOfRows() * m_lineHeight
;
611 SetVirtualSize( width
, height
);
612 GetOwner()->SetScrollRate( 10, m_lineHeight
);
617 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
619 wxWindow::ScrollWindow( dx
, dy
, rect
);
620 GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 );
623 void wxDataViewMainWindow::OnPaint( wxPaintEvent
&event
)
625 wxPaintDC
dc( this );
627 GetOwner()->PrepareDC( dc
);
629 dc
.SetFont( GetFont() );
631 dc
.DrawText( wxT("main window"), 5, 5 );
634 void wxDataViewMainWindow::OnMouse( wxMouseEvent
&event
)
639 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent
&event
)
644 //-----------------------------------------------------------------------------
646 //-----------------------------------------------------------------------------
648 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
)
650 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
)
651 EVT_SIZE(wxDataViewCtrl::OnSize
)
654 wxDataViewCtrl::~wxDataViewCtrl()
657 GetModel()->RemoveNotifier( m_notifier
);
660 void wxDataViewCtrl::Init()
665 bool wxDataViewCtrl::Create(wxWindow
*parent
, wxWindowID id
,
666 const wxPoint
& pos
, const wxSize
& size
,
667 long style
, const wxValidator
& validator
)
669 if (!wxControl::Create( parent
, id
, pos
, size
, style
| wxScrolledWindowStyle
|wxSUNKEN_BORDER
, validator
))
675 MacSetClipChildren( true ) ;
678 m_clientArea
= new wxDataViewMainWindow( this, -1 );
679 m_headerArea
= new wxDataViewHeaderWindow( this, -1, wxDefaultPosition
, wxSize(-1,25) );
681 SetTargetWindow( m_clientArea
);
683 wxBoxSizer
*sizer
= new wxBoxSizer( wxVERTICAL
);
684 sizer
->Add( m_headerArea
, 0, wxGROW
);
685 sizer
->Add( m_clientArea
, 1, wxGROW
);
692 WXLRESULT
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
,
696 WXLRESULT rc
= wxPanel::MSWWindowProc(nMsg
, wParam
, lParam
);
699 // we need to process arrows ourselves for scrolling
700 if ( nMsg
== WM_GETDLGCODE
)
702 rc
|= DLGC_WANTARROWS
;
710 void wxDataViewCtrl::OnSize( wxSizeEvent
&event
)
712 // We need to override OnSize so that our scrolled
713 // window a) does call Layout() to use sizers for
714 // positioning the controls but b) does not query
715 // the sizer for their size and use that for setting
716 // the scrollable area as set that ourselves by
717 // calling SetScrollbar() further down.
724 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel
*model
)
726 if (!wxDataViewCtrlBase::AssociateModel( model
))
729 m_notifier
= new wxGenericDataViewListModelNotifier( model
);
731 model
->AddNotifier( m_notifier
);
733 m_clientArea
->UpdateDisplay();
738 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn
*col
)
740 if (!wxDataViewCtrlBase::AppendColumn(col
))
743 m_clientArea
->UpdateDisplay();
749 // !wxUSE_GENERICDATAVIEWCTRL
752 // wxUSE_DATAVIEWCTRL